题意:给定n个带标号的正方形,标号要么是一个大写字母加一个+或-,要么是00,
当且仅当大写字母相同并且符号相反时可以连接,问你给定的能不能拼成一个无限大的的东西。
析:说实话,真心没有看出来是拓扑排序,后来知道是,可是还是不会写。
既然要拼成无限大,那么只要拼的时候拼出一个环来,又由于每个是无限多的,那么可以一直重复,
就能拼起来无限大的东西,把每个正方形看成一条边,那么不就是一个拓扑排序,看看能不能找到一个环么,
如果能找到,那么就可以,找不到,就不可以。注意的是正方形可以从四面都拼,所以要注意考虑全了,
刚开始,忘了,只考虑了两端,WA。把每个边都标记一下就好,相当于构造出一个图来。
代码如下:
#include <iostream> #include <cstdio> #include <vector> #include <cstring> using namespace std; const int maxn = 55; int G[maxn][maxn], c[maxn]; char s[10]; int getid(char a, char b) { return (a - 'A')* 2 + ('+' == b ? 1 : 0); } void solve(char a1, char a2, char b1, char b2){ if('0' == a1 || '0' == b1) return ; int u = getid(a1, a2) ^ 1; int v = getid(b1, b2); G[u][v] = 1;//构造边 G[v^1][u^1] = 1;//构造反向边 } bool dfs(int u){ c[u] = -1;//作标记,正在访问 for(int v = 0; v < 52; ++v) if(G[u][v]){ if(c[v] < 0) return false;//存在有向环 else if(!c[v] && !dfs(v)) return false; } c[u] = 1; return true; } bool toposort(){ memset(c, 0, sizeof(c)); for(int i = 0; i < 52; ++i) if(!dfs(i)) return true; return false; } int main(){ int n; while(scanf("%d", &n) == 1){ memset(G, 0, sizeof(G)); for(int i = 0; i < n; ++i){ scanf("%s", s); solve(s[0], s[1], s[2], s[3]);//考虑全了 solve(s[4], s[5], s[6], s[7]); solve(s[0], s[1], s[4], s[5]); solve(s[0], s[1], s[6], s[7]); solve(s[2], s[3], s[4], s[5]); solve(s[2], s[3], s[6], s[7]); } if(toposort()) puts("unbounded"); else puts("bounded"); } return 0; }