紫书172的例题:
题目大意:有n种正放形,每种正方形的数量可视为无限多。已知边与边之间的结合规则,而且正方形可以任意旋转和反转,问这n中正方形是否可以拼成无限大的图案
思路:首先因为是要无穷大,所以只要正方形之间的连接出现有向环及说明可以无限。但是如果单纯的对正方形进行枚举肯定会TLE,因此我们换一个思路。
首先有没有正方形是无所谓的,如果有一个是A-另外一个正方形里面有A+,管他是哪个正方形,只要能连过去就行了,反正只要最后如果能连回来就说明有环。
所以我们把所有的字母看成点,然后让正方形中每个字母进行连线即可。最后利用拓扑序和染色法求解是否存在环即可。
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second const int maxn = 40000 + 5; int n; bool G[100][100]; int cal(char a, char b){ int res = (a - 'A') * 2 + (b == '+' ? 0 : 1); return res; } void connect(char a1, char a2, char b1, char b2){ int u = cal(a1, a2) ^ 1, v = cal(b1, b2); G[u][v] = 1; } int vis[100]; bool dfs(int u){ vis[u] = -1; for (int i = 0; i < 52; i++){ if (G[u][i]){ if (vis[i] < 0) return true; else if(!vis[i] && dfs(i)){ return true; } } } vis[u] = 1; return false; } bool find_cir(){ memset(vis, 0, sizeof(vis)); for (int i = 0; i < 52; i++){ if (!vis[i] && dfs(i)) return true; } return false; } int main(){ while (scanf("%d", &n) == 1 && n){ memset(G, false, sizeof(G)); char ch[10]; for (int i = 1; i <= n; i++){ scanf("%s", ch); for (int i = 0; i < 4; i++){ for (int j = 0; j < 4; j++){ if (i == j || ch[i * 2] == '0' || ch[j * 2] == '0') continue; connect(ch[i * 2], ch[i * 2 + 1], ch[j * 2], ch[j * 2 + 1]); } } } if (find_cir()) printf("unbounded\n"); else printf("bounded\n"); } return 0; }