做拓扑排序的题目,首先要知道两条定理:
1、最后得到的拓扑数组的元素个数如果小于n,则不存在拓扑序列。 (有圈)
2、如果一次入队的入度为零的点数大于1,则拓扑序列不唯一。 (关系不确定)
本题有一个默认的东西,如果到了第K(看K<m)步,能唯一确定一个序列,就不用管之后会不会产生矛盾。
这题的思路还是比较清晰的。输入也只有X<Y(只有<符号,并且X,Y都只是大写字母),数据量比较小。不过边数没有限制,用链式前向星的话不太好,还是用邻接矩阵吧。每次用邻接矩阵要注意的是判断重边,做小生成树的时候是用初始化边为无穷大,然后每次取小的。但是这里没有边权,所以只要有边,赋值为1,就可以了。遇到重边的话,不能再加入度。
只需要拓扑排序就可以解决这个问题了。我就犯了画蛇添足的错误,我居然用floyd去判圈。这主要是对拓扑排序理解不够的原因。当出现的字母的数字小于n时,没出现的字母的入度是零,所以不影响拓扑排序产生的数据元素的个数。只有有圈的情况才会使得数组元素个数小于n。
还有,我犯了一个很二的错误。因为没输入一组数据就要做一次拓扑排序。我居然把统计入度的数组没有变化就用了。囧了。再声明一个数组,每次拓扑排序之前,把入度数组的数据复制过来就好了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 const int N = 30; 7 int ind[N],que[N], g[N][N],id[N]; 8 int iq,flag, T; 9 void topo(int n) 10 { 11 int i,k,j=0,x; 12 T=0; 13 for(i=1;i<=n;i++) 14 { 15 id[i]=ind[i]; 16 if(id[i]==0) que[j++]=i; 17 } 18 if(j>1) T=1; 19 x=j; 20 for(i=0;i<j;i++) 21 { 22 if(j-x>1) T=1; 23 x=j; 24 int u=que[i]; 25 for(k=1;k<=n;k++) 26 { 27 if(g[u][k]&&u!=k) 28 { 29 id[k]--; 30 if(id[k]==0) que[j++]=k; 31 } 32 } 33 } 34 iq=j; 35 } 36 void init() 37 { 38 flag=0; 39 memset(ind,0,sizeof(ind)); 40 memset(g,0,sizeof(g)); 41 } 42 int main() 43 { 44 //freopen("test.txt","r",stdin); 45 int n,m,i,j,k,t,a,b; 46 char ch1,ch2,ch; 47 while(scanf("%d%d",&n,&m)!=EOF) 48 { 49 if(!n) break; 50 init(); 51 t=0; 52 for(k=1;k<=m;k++) 53 { 54 do 55 scanf("%c",&ch1); 56 while (!isalpha(ch1)) ; 57 scanf("<%c",&ch2); 58 if(flag) continue; 59 a=ch1-64,b=ch2-64; 60 if(a>n||b>n||a==b) flag=1; 61 if(flag) {printf("Inconsistency found after %d relations. ",k);continue;} 62 if(g[a][b]) continue; 63 g[a][b]=1; 64 ind[b]++; 65 topo(n); 66 if(iq<n){flag=1;printf("Inconsistency found after %d relations. ",k);continue;} 67 if(iq==n&&!T){ 68 flag=1; 69 printf("Sorted sequence determined after %d relations: ",k); 70 for(i=0;i<n;i++) printf("%c",que[i]+64); 71 printf(". "); 72 continue; 73 } 74 if(k==m&&!flag) printf("Sorted sequence cannot be determined. "); 75 } 76 } 77 return 0; 78 }