HDOJ 2007 Summer Exercise(2)
按照题意进行模拟,建一个图,排名高的连一条边到排名低的,最终合法的图应该是朝着一个方向的。很容易想到拓扑排序。相等的两个玩家就并查集起来。用BFS拓排,用入度为零的点初始化队列,删去它连出的边,终点入度减一,然后判断终点是否入度为零。若是,则入队。若存在点无法入队,说明有环,则CONFLICT。
然后就是实现上的一些小细节。
(1)先并查集,再建图可以防止状态混乱代码混乱以及思维混乱。
(2)如果两个玩家并起来了,便不会入队。要考虑需要入队的人数要不要减一。
(3)UNCERTAIN的情况是,初始化队列的时候,或者拓扑一个点的时候,有两名或以上的玩家同时入队。因为这几人无法比大小。
#include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int maxn=10000+10, maxm=20000+10; int n,m; int innum,tot; int inpt[maxm][2]; int edge[maxm][3]; int ghead[maxn],last[maxn],ind[maxn],otd[maxn]; int que[2*maxn]; int gf(int); void adde(int,int,int); int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d\n", &n, &m) != EOF) { innum = 0; tot = n; memset(ind, 0, sizeof(ind)); memset(otd, 0, sizeof(otd)); memset(last, 0, sizeof(last)); for(int i=0; i<n; i++) ghead[i] = i; int a,b; char mid[3]; for(int i=1; i<=m; i++) { scanf("%d %s %d\n", &a, mid, &b); if(mid[0] == '=') { if(ghead[gf(a)]!=ghead[gf(b)]) tot--; ghead[gf(a)] = ghead[gf(b)]; } else { innum++; if(mid[0] == '>') { inpt[innum][0]=a; inpt[innum][1]=b; } else { inpt[innum][0]=b; inpt[innum][1]=a; } } } for(int i=1; i<=innum; i++) { int u = gf(inpt[i][0]); int v = gf(inpt[i][1]); adde(u,v,i); } bool unk=0; int qhead=0,qtail=0; for(int i=0; i<n; i++) { if(!ind[i]&&i==gf(i)) que[++qtail] = i; } if(qtail>1) unk=1; while(qhead<qtail) { int u = que[++qhead]; tot--; int one = 0; for(int e=last[u]; e; e=edge[e][2]) { int v = edge[e][1]; otd[u]--; ind[v]--; if(!ind[v]) { que[++qtail] = v; one++; } } if(one>1) unk=1; } if(tot) puts("CONFLICT"); else if(unk) puts("UNCERTAIN"); else puts("OK"); } return 0; } void adde(int u, int v, int i) { otd[u]++; ind[v]++; edge[i][0]=u; edge[i][1]=v; edge[i][2]=last[u]; last[u]=i; return; } int gf(int x) { if(x==ghead[x]) return x; return ghead[x]=gf(ghead[x]); }