题目链接。
题目大意:
给定一定的数量的小于关系:
1.如果发现环,输出从前几次就可以确定出现环
2.如果能够确定唯一序列,输出。
3.如果通过全部关系,还不能确定序列,则输出不能确定.
分析:
个人感觉难点在于判环上。
1.如果每次都只能找到1个入度为0的点,并能确定序列,则该序列即为答案。
2.如果每次查找时,发现两个及其以上的入度为0的点,则表明一定不能确定唯一序列(即存在环或者是不能确定)。如果可以确定一个任意序列,即表明还需要更多关系。如果继续查找下去,找不到入度为0的点,则存在环。
AC代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; const int maxn = 500; const int INF = (1<<29); int n, m, indeg[maxn], S[maxn], top, mark; bool G[maxn][maxn], v[maxn]; int toposort() { int deg[maxn], cn; bool vis[maxn], flag = true; top = 0; memcpy(deg, indeg, sizeof(deg)); memset(vis, 0, sizeof(vis)); for(int i=0; i<n; i++) { cn = 0; for(int k=0; k<n; k++) if(deg[k] == 0) cn++; //计算入度为0的点的个数 if(cn > 1) flag = false; //出现环或者不能确定唯一序列 else if(cn == 0) break; //出现环 int k; for(k=0; k<n; k++) if(deg[k] == 0) break; S[top++] = k; deg[k]--; for(int j=0; j<n; j++) if(G[k][j]) deg[j]--; } if(cn == 0) return -1; //环 if(mark < n || !flag) return 0; //不能判断 else return 1; //拓扑成功 } int main() { char c1, c2; int flag, num; // freopen("my.txt", "r", stdin); while(scanf("%d %d", &n, &m) == 2) { if(n == 0 && m == 0) break; memset(indeg, 0, sizeof(indeg)); memset(G, false, sizeof(G)); memset(v, false, sizeof(v)); flag = 0; mark = 0; for(int i=0; i<m; i++) { getchar(); scanf("%c<%c", &c1, &c2); if(!G[c1-'A'][c2-'A']) { G[c1-'A'][c2-'A'] = true; indeg[c2-'A']++; } //mark用来标记当前已经出现的字母的个数 if(!v[c1-'A']) { v[c1-'A'] = true; mark++; } if(!v[c2-'A']) { v[c2-'A'] = true; mark++; } int res; if(flag == 0) { res = toposort(); if(res == -1) { flag = -1; num = i; } else if(res == 1) { num = i; flag = 1; } } } if(flag == 1) { printf("Sorted sequence determined after %d relations: ", num+1); for(int i=0; i<top; i++) { putchar(S[i]+'A'); } printf(". "); } else if(flag == 0) printf("Sorted sequence cannot be determined. "); else printf("Inconsistency found after %d relations. ", num+1); } return 0; }