Rank of Tetris HDU - 1811
考察:并查集+拓扑序列+离线处理
难点在于并查集如何运用,我是卡在如何判断条件不足那里卡了很久.拓扑序列处理不了等号问题.如果用队列中无根结点的元素>2来判断条件不足的话,也存在相等利用序号大小排列名次的问题.因此这题就没写出来...
错误思路1:
利用并查集判矛盾,利用拓扑序列判断是否无法判断.这个思路是参考直接的食物链设置距离数组.但是这道题a>b,b>c说明a>c这个在并查集里会判断a=c,因此这道题的距离并不是3个一循环所以错误
正确思路 :
很容易想到成环判断是否矛盾,条件不足的情况就是无根节点是否有1个以上
需要处理的就是无根结点到底有没有等号关系,暴力枚举一定TLE.但是这道题相等具有传递性,因此可以用并查集维护.
易错:
必须先将等号关系的元素先加到集合里,再将所有相等的元素的邻接表元素全部接到根节点.
- 加入等号关系意味着拓扑序列的元素减少,必须判重避免多减
- 用SET的pair判重会WA...原因是当已经并在集合里的元素set会多算一次
1 #include <iostream> 2 #include <queue> 3 #include <algorithm> 4 using namespace std; 5 const int N = 1e5+10; 6 const int M = 2e5+10; 7 int h[N],e[M],ne[M],d[M],p[N],idx,m,n,sum; 8 int l[M],r[M]; 9 char op[M]; 10 void add(int a,int b) 11 { 12 e[idx]=b,ne[idx]=h[a],h[a]=idx++; 13 } 14 int findf(int x) 15 { 16 if(x!=p[x]) p[x] = findf(p[x]); 17 return p[x]; 18 } 19 void inits() 20 { 21 fill(d,d+M,0); fill(h,h+N,-1); 22 idx = 0; sum = 0; 23 for(int i=0;i<n;i++) p[i]=i; 24 } 25 int merge(int a,int b) 26 { 27 int x=findf(a); 28 int y=findf(b); 29 if(x==y) return 0;//set去重的错误原因 30 p[x] = y; 31 return 1; 32 } 33 void topsort() 34 { 35 queue<int> q; 36 bool unsure = false; 37 for(int i=0;i<n;i++) if(!d[i]&&findf(i)==i) q.push(i);//我真的好菜... 38 while(!q.empty()) 39 { 40 int sz = q.size(); 41 if(sz>1) unsure = 1; 42 sum+=sz; 43 while(sz--) 44 { 45 int x = q.front(); 46 q.pop(); 47 for(int i=h[x];i!=-1;i=ne[i]) 48 { 49 int j = e[i]; d[j]--; 50 if(!d[j]) q.push(j); 51 } 52 } 53 } 54 if(sum!=n) printf("CONFLICT\n"); 55 else if(unsure) printf("UNCERTAIN\n"); 56 else printf("OK\n"); 57 } 58 int main() 59 { 60 // freopen("in.txt","r",stdin); 61 while(scanf("%d%d",&n,&m)!=EOF) 62 { 63 inits(); 64 for(int i=0;i<m;i++) 65 { 66 scanf("%d %c %d",&l[i],&op[i],&r[i]); 67 if(op[i]=='=') 68 if(merge(l[i],r[i])) sum++; 69 } 70 for(int i=0;i<m;i++) 71 { 72 int px = findf(l[i]); int py = findf(r[i]); 73 if(op[i]=='<') { add(py,px); d[px]++;} 74 else if(op[i]=='>') { add(px,py); d[py]++;} 75 } 76 topsort(); 77 } 78 return 0; 79 }