题目大意:
对于给定的前n个字母( A-... ),给出可能的字母间的偏序,问是否能确定构成一个线性序T,如果能或不能,则给出最早能做出判断的偏序在第几个。否则说明不可判。
这道题有点犀利,弄了半个晚上。一开始思维没打开,找不到思路,最后想到判断可达性的复杂度不可能比DFS传递闭包更好,因此果断改变思路。可以顺序读入每个偏序,对于每次读入,构造一次拓扑排序,那么在第几个偏序出解,结果就在第几。
注意容易出现的逻辑错误,首先就是“判断是否能构成T序”的优先级高于T是否唯一,也就是说当出现多个可随意次序的点时,不能马上输出不唯一,需要将拓扑排序做完以保证没有成环,判环优先级更高。
算法可以顺序读入偏序,随之做拓扑拆边,当遇到栈尺寸大于1(多个不可比),不可比标记置一。拓扑结束后,若成环,则输出成环,否则输出T唯一或继续读入偏序(当前不唯一)。若始终不成环且不唯一,最终结果自然不唯一。
4 4
A<B
C<B
D<B
B<A
Inconsistency found after 4 relations.
1#include<cstdio>
2#include<cstdlib>
3#include<cstring>
4#include<stack>
5using namespace std;
6int g[26][26],degree[26],degreeR[26],path[26];
7bool ring,more;
8int n,m;
9int main(){
10 int i,j,k,t;
11 char u,v;
12 int ele;
13 bool sure,unsure;
14 while(scanf("%d%d",&n,&m),n|m){
15 memset(g,0,sizeof(g));
16 memset(degreeR,0,sizeof(degreeR));
17 sure = false;
18 for(getchar(),i=0;i<m;i++){
19 scanf("%c<%c",&u,&v);getchar();
20
21 g[ u-'A' ][ v-'A' ]=1;
22 degreeR[ v-'A' ]++;
23 stack<int> _sta;
24 for(j=0;j<n;j++) if( degreeR[j] == 0 ) _sta.push(j);
25
26 for(j=0;j<n;j++) degree[j]=degreeR[j];
27 more=false;
28 ring=false;
29 for(j=0;j<n;j++){
30 if( _sta.size()>1 ) more=true; // unsure
31 if( _sta.empty() ){ ring=true; break; } // ring
32 ele = _sta.top(); _sta.pop();
33 path[j]=ele;
34 for(k=0;k<n;k++){
35 if( g[ele][k]!=0 && --degree[k] == 0 ) { _sta.push(k); }
36 }
37 }
38
39 if( j == n && more == false){
40 printf("Sorted sequence determined after %d relations: ",i+1);
41 for(j=0;j<n;j++) printf("%c",'A'+path[j]); printf(".\n");
42 sure=true;
43 break;
44 }
45 else if( ring == true ){ printf("Inconsistency found after %d relations.\n",i+1); sure=true; break; }
46 }
47 if( sure == false ) printf("Sorted sequence cannot be determined.\n");
48 for(t=i+1;t<m;t++){ scanf("%c<%c",&u,&v); getchar(); }
49 }
50 return 0;
51}
52