Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1827 Accepted Submission(s): 487
3 3 0 > 1 1 < 2 0 > 2 4 4 1 = 2 1 > 3 2 > 0 0 > 1 3 3 1 > 0 1 > 2 2 < 1
OK CONFLICT UNCERTAIN
此题的点很多,不能用矩阵,当时不会用链表写,百度看了别人的解题报告,发现那个链表和邻接表差不多,就试试用链表来写了。有>、=、<三种表示方法,如果=的话直接并查集把它当作是那个点的祖先。还有就是用队列来拓扑排序,这样比较快,而且比较方便,还发现了拓扑排序的一些特点:
1.当队列Q.size() > 1,证明这个高手榜不能确定排名,因为两个以上的deg[]为0了,那几个人谁先谁后无法判断。
2.当队列结束后,如果进队列的次数少于n,证明此图有环,排名有冲突。
3.若进队列次数等于n,证明可以知道此图是单向无环图。
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1811
代码:
#include <iostream> #include <stdio.h> #include <memory.h> #include <queue> using namespace std; const int N = 10005; const int M = 20005; struct edge { int val; edge *next; }*e[N]; edge memory[M]; int cnt; bool flag, tar; char O[N]; int L[N], R[N]; int fa[N], deg[N]; int n, m; void init() { cnt = 0; tar = flag = false; for(int i = 0; i < n; i++) { fa[i] = i; e[i] = NULL; deg[i] = 0; } } int find(int x) { if(x != fa[x]) { x = find(fa[x]); } return fa[x]; } void Union(int x, int y) { fa[x] = y; } void add(int u, int v) { edge *p = &memory[cnt++]; p->val = v; p->next = e[u]; e[u] = p; } int main() { int i, k, fx, fy, num; while(scanf("%d %d", &n, &m) != EOF) { init(); num = n; for(i = 0; i < m; i++) { scanf("%d %c %d", &L[i], &O[i], &R[i]); if(O[i] == '=') { fx = find(L[i]); fy = find(R[i]); if(fx != fy) { Union(fx, fy); num--; } } } for(i = 0; i < m; i++) { if(O[i] == '=') continue; fx = find(L[i]); fy = find(R[i]); if(fx == fy) flag = true; if(O[i] == '>') { add(fx, fy); deg[fy]++; } else { add(fy, fx); deg[fx]++; } } if(flag) { printf("CONFLICT\n"); continue; } queue<int> Q; for(i = 0; i < n; i++) { if(deg[i]==0 && i==find(i)) Q.push(i); } while(!Q.empty()) { if(Q.size() > 1) tar = true; k = Q.front(); Q.pop(); num--; for(edge *p = e[k]; p; p = p->next) { if(--deg[p->val] == 0) { Q.push(p->val); } } } if(num > 1) printf("CONFLICT\n"); else if(tar) printf("UNCERTAIN\n"); else printf("OK\n"); } return 0; }