<题目链接>
题目大意:
对于N个大写字母,给定它们的一些关系,要求判断出经过多少个关系之后可以确定它们的排序或者排序存在冲突,或者所有的偏序关系用上之后依旧无法确定唯一的排序。
解题分析:
因为本题在确定发生冲突和能够确定唯一排序的时候要及时输出,所以必然是每输入一对关系,就进行一次拓扑排序来判断。然后判断冲突就是判断是否存在环,判断是否能够确定唯一排序就是在不存在环的情况下,同时任何时候都不存在多个入度为0点。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 using namespace std; 6 const int N = 50; 7 int ind[N],output[N]; 8 bool g[N][N]; //临接矩阵此题可以随便用 9 int n,m,ans,loc; 10 bool circle,order; 11 12 int topsort( int n ) { 13 queue<int>Q; 14 int inorder = true; 15 int num = 0,temp[N]; 16 memcpy(temp,ind,sizeof(ind)); //复制当前所有点的入度,防止下面的操作对其造成影响 17 for( int i = 0; i < n; i++ ) { //将所有入度为0的点入队列 18 if( !ind[i] ) Q.push(i); 19 } 20 while( !Q.empty() ) { 21 if( Q.size() > 1 )inorder = false; //判断是否存在同时有多个入度为0的点的情况 22 int cur = Q.front();Q.pop(); 23 output[++num] = cur; //num计数 以存到out里面 24 for(int i = 0; i < n; i++ ) 25 if(g[cur][i]==1 && --temp[i] == 0) 26 Q.push(i); 27 } 28 if( num != n ) return 1; //存在环,即发生冲突 29 if( !inorder ) return 0; //不能确定唯一顺序 30 return -1; //能够确定唯一顺序 31 } 32 int main(){ 33 char s[10]; 34 while( scanf("%d%d", &n, &m) != EOF && n ){ 35 circle=order=false; 36 memset(g,0,sizeof(g)); 37 memset(ind,0,sizeof(ind)); 38 for( int i = 1; i <= m; i++ ){ 39 scanf("%s", s); 40 if( !circle && !order ){ //已经产生冲突或者已经能够确定排序,就不用读入了 41 int u=s[0]-'A',v=s[2]-'A'; //注意这里,所有点的编号是从0~n-1 42 if(g[u][v] == 0){ 43 g[u][v] = 1;ind[v]++; 44 } 45 ans = topsort(n); 46 if( ans == 1 ){ 47 circle = true; 48 printf("Inconsistency found after %d relations. ", i); 49 } 50 else if( ans == -1 ){ 51 order = true; 52 loc=i; //记录位置 53 } 54 } 55 } 56 if(!circle && !order ) //如果没有产生环,并且不能够确定唯一的顺序 57 printf("Sorted sequence cannot be determined. "); 58 else if(order){ //能够确定唯一的顺序 59 printf("Sorted sequence determined after %d relations: ", loc); 60 for(int i=1; i<=n; i++)printf("%c", output[i]+'A');puts("."); 61 } 62 } 63 }
2018-11-21