洛谷P1347 排序html
講真,我認爲題面是有一點問題的:node
題目中有這樣一些語句「若根據前x個關係即發現存在矛盾(如A<B,B<C,C<A),輸出:Inconsistency found after 2 relations.」 和 「提示:肯定n個元素的順序後便可結束程序,能夠不用考慮肯定順序以後出現矛盾的狀況」c++
首先,那個輸出應該是「Inconsistency found after x relations.」算法
其次,已知\(A<B,B<C\),根據那個提示咱們能夠直接判斷\(A<B<C\)而後後面的\(C<A\)則能夠不用管了,可是題目解釋的倒是不合法編程
以上是個人想法,我在編程中按照提示編的(AC了),因此題意爭議大概不影響作題?(大霧...)數組
好了,廢話很少說,這道題我會用兩種作法完成:拓撲排序、變種Floyd學習
由於題目中的規則就是元素之間的順序而且是有向圖(仍是無並列關係的順序),因此可使用拓撲排序.net
由於要求輸出第\(i\)步要麼完成排序要麼造成環,因此每輸入一組大小關係就要進行一次拓撲排序code
這題之因此是藍題,大概就是由於每次拓撲排序須要處理三種狀況:
1. 造成合法拓撲序列
2. 造成非法的環
3. 暫時沒有造成完整的拓撲序列但也不是環
(注意拓撲排序不處理題目中的第三種狀況,即沒法肯定的狀況)
題目中的第三種狀況是最簡單的:當輸入完成後尚未輸出則說明沒法肯定出拓撲序列
下面重點講拓撲排序中的三種狀況
①輸入的兩個元素\(u\)、\(v\)相同(自環)
②答案數組的長度\(<\)目前所出現過的元素個數(下面會給出說明)
①不知足以上造成環的條件
②答案數組的長度\(==N\)(標準的拓撲排序合法判斷)
①在最開始入隊時,同時存在多個入度爲0的點
②在循環隊列處理中,有超過1個的點在同一輪入隊
答案數組的長度\(<\)目前所出現過的元素個數(造成環),如圖:
在最開始入隊時,同時存在多個入度爲0的點(暫時不造成)
由於題目已經說明拓撲序列沒有並列關係,因此這題一個合法的序列不可能同時存在兩個源點(即入度爲0的點)
同上,由於沒有並列關係,因此一個點的後繼應該只有一個而不是多個,那麼一次只能入隊一個,若是一次入隊多個則說明當前還不造成合法序列
註釋版配合上面的講解,敲詳細呀qwq~
#include <bits/stdc++.h> using namespace std; queue<int> q; char a,b,op; vector<int> ans; int n,m,tot,sum,in[1001],inn[1001],head[1001],flag[1001]; struct node { int to,net; } e[1001]; inline void add(int u,int v) { e[++tot].to=v; e[tot].net=head[u]; head[u]=tot; } inline int check() { //拓撲排序 ans.clear(); //必定要清空 int k=0,kk=0; for(register int i=1;i<=n;i++) { inn[i]=in[i]; //由於隊列處理會影響in[],因此要賦值 if(in[i]==0&&flag[i]==1) { if(k==0) k=1; else kk=1; //若是kk=1,則說明同時存在多個入度爲0的點 q.push(i); } } if(q.empty()) return 1; //隊列爲空,說明是環 while(!q.empty()) { int k=0,now=q.front(); //這裏k要從新賦爲0 q.pop(); ans.push_back(now); //存入答案數組 for(register int i=head[now];i;i=e[i].net) { int v=e[i].to; if(--inn[v]==0) { if(k==0) k=1; else kk=1; //若是kk=1,則說明一次入隊多個點 q.push(v); } } } if(ans.size()<sum) return 1; //答案數組的長度<目前出現過的全部元素,造成環 if(kk==1) return 2; return 0; } int main() { scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++) { cin>>a>>op>>b; if(a==b) { //自環的狀況 printf("Inconsistency found after %d relations.",i); return 0; } add(a-'A'+1,b-'A'+1); //連邊 in[b-'A'+1]++; //後者的入度++ if(flag[a-'A'+1]==0) sum++; //統計當前出現過的不重複的元素個數 if(flag[b-'A'+1]==0) sum++; flag[a-'A'+1]=flag[b-'A'+1]=1; int x=check(); if(x==1) { //環的狀況 printf("Inconsistency found after %d relations.",i); return 0; } if(ans.size()==n&&x==0) { //造成了合法的拓撲序列 printf("Sorted sequence determined after %d relations: ",i); for(register int i=0;i<ans.size();i++) cout<<char(ans[i]+'A'-1); printf("."); return 0; } } printf("Sorted sequence cannot be determined."); //最終的無解狀況 return 0; }
由於我本人是用的是拓撲排序,而變種Floyd是右邊dalao作出來的,因此這裏直接掛出dalao的題解