P1347 排序
题目描述
一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D。在这道题中,我们将给你一系列形如A<B的关系,并要求你判断是否能够根据这些关系确定这个数列的顺序。
输入输出格式
输入格式:
第一行有两个整数n,m,n表示需要排序的元素数量,2<=n<=26,第1到n个元素将用大写的A,B,C,D....表示。m表示将给出的形如A<B的关系的数量。
接下来有m行,每行有3个字符,分别为一个大写字母,一个<符号,一个大写字母,表示两个元素之间的关系。
输出格式:
若根据前x个关系即可确定这n个元素的顺序yyy..y(如ABC),输出
Sorted sequence determined after xxx relations: yyy...y.
若根据前x个关系即发现存在矛盾(如A<B,B<C,C<A),输出
Inconsistency found after 2 relations.
若根据这m个关系无法确定这n个元素的顺序,输出
Sorted sequence cannot be determined.
(提示:确定n个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况)
输入输出样例
这道题我来提供一种tarjan+拓扑排序的做法,首先我们考虑满足第二种情况的序列,如果存在矛盾,那么这个图中一定存在环,这样我们就可以用tarjan缩点判断一下是否存在环,有一点需要注意,就是如果小于号两边的数相同,那么就一定产生矛盾(非常坑)。对于第一种情况的序列,不难看出这个序列的拓扑序一定是唯一的,而且一定不存在环,也就是说每次拓扑时在栈中的元素一定只有唯一的一个,这样只需在每次拓扑开始时判断一下元素个数即可。如果第一和第二种情况均不满足,那么一定就是第三种情况咯。
最后附上代码:
1 #include<iostream> 2 #include<string> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<stack> 7 #define maxn 1005 8 using namespace std; 9 10 struct edge 11 { 12 int next; 13 int to; 14 }g[maxn<<1]; 15 int n,m,num,col,tot,cnt,pd,cnt2,cc,pd1; 16 int last[maxn],de[maxn],dfn[maxn],low[maxn],co[maxn],de1[maxn]; 17 char aa[5],bb[maxn]; 18 stack<int>s; 19 stack<int>ss; 20 21 void add(int from,int to) 22 { 23 g[++num].next=last[from]; 24 g[num].to=to; 25 last[from]=num; 26 } 27 28 void topo() 29 { 30 for(int i=1;i<=n;i++) 31 { 32 if(de1[i]==0) 33 { 34 ss.push(i); 35 } 36 } 37 while(ss.size()) 38 { 39 if(ss.size()>1)//如果栈中多余一个元素,说明topo序不唯一 40 { 41 pd1=1; 42 break; 43 } 44 int u=ss.top();ss.pop(); 45 bb[++cc]=char(u+'A'-1); 46 for(int i=last[u];i;i=g[i].next) 47 { 48 int v=g[i].to; 49 de1[v]--; 50 if(de1[v]==0) 51 { 52 ss.push(v); 53 } 54 } 55 } 56 } 57 58 void tarjan(int u) 59 { 60 dfn[u]=low[u]=++tot; 61 s.push(u); 62 for(int i=last[u];i;i=g[i].next) 63 { 64 int v=g[i].to; 65 if(!dfn[v]) 66 { 67 tarjan(v); 68 low[u]=min(low[u],low[v]); 69 } 70 else if(!co[v]) 71 { 72 low[u]=min(low[u],dfn[v]); 73 } 74 } 75 if(low[u]==dfn[u]) 76 { 77 col++;cnt=0; 78 for(;;) 79 { 80 int x=s.top();s.pop(); 81 co[x]=col; 82 cnt++; 83 if(cnt>1) pd=1;//如果一个强联通分量中存在不止一个点,说明有环 84 if(x==u) break; 85 } 86 } 87 } 88 89 int main() 90 { 91 scanf("%d%d",&n,&m); 92 for(int i=1;i<=m;i++) 93 { 94 scanf("%s",aa); 95 add(aa[0]-'A'+1,aa[2]-'A'+1); 96 if(aa[0]-'A'+1==aa[2]-'A'+1) 97 { 98 printf("Inconsistency found after %d relations.",i);//这里需要特判一下,不然第一个点会wa 99 return 0; 100 } 101 de[aa[2]-'A'+1]++; 102 de1[aa[2]-'A'+1]=de[aa[2]-'A'+1]; 103 for(int j=1;j<=n;j++) 104 de1[j]=de[j]; 105 tot=0;col=0;cc=0;pd1=0; 106 memset(co,0,sizeof(co)); 107 memset(dfn,0,sizeof(dfn)); 108 memset(low,0,sizeof(low)); 109 while(s.size()) s.pop(); 110 while(ss.size()) ss.pop(); 111 for(int j=1;j<=n;j++) 112 { 113 if(!dfn[j]) 114 { 115 tarjan(j);//tarjan判环 116 } 117 } 118 if(pd==1) 119 { 120 printf("Inconsistency found after %d relations.",i); 121 return 0; 122 } 123 topo();//topo检查topo序是否唯一 124 if(pd1==0) 125 { 126 printf("Sorted sequence determined after %d relations: ",i); 127 for(int j=1;j<=n;j++) 128 { 129 printf("%c",bb[j]); 130 } 131 printf("."); 132 return 0; 133 } 134 } 135 printf("Sorted sequence cannot be determined."); 136 return 0; 137 }