BZOJ 3953 Self-Assembly 解题报告
首先,我们可以先考虑一个暴力一点的算法:
对于任意两个分子,如果它们能以至少一种进行匹配,那么我们就在这两个分子之间连一条边。
然后如果我们能找到一个环,就说明是 unbounded,否则就是 bounded。
复杂度是 $O(n^2)$ 的,然而 $n \le 40000$ ,显然是不行的。
考虑优化。我们注意到本质不同的边有 $26$ 种,那么我们应该能省去很多不必要的边。
令 $inv(x)$ 为与类型为 $x$ 的离子匹配的离子,如 $inv(A+)=A-$。
对于在同一个分子上的两个离子 $x$ 和 $y$ ,连有向边 $x\rightarrow inv(y)$ 和 $y\rightarrow inv(x)$。
然后只要判断这个图是否有环即可。
然后这个图只有 $52$ 个点,不是想怎么搞就怎么搞嘛。。。
(感谢 HZC 的谆谆教诲)
毕竟 Gromah 太弱,再一次 WA 到死。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 #define D 52 + 5 10 11 int n; 12 int q[D]; 13 bool Flag[D]; 14 bool Map[D][D]; 15 char s[9]; 16 17 inline int get(char ch_1, char ch_2) 18 { 19 if (ch_1 == '0') return -1; 20 return (ch_1 - 'A') << 1 | (ch_2 == '+'); 21 } 22 23 inline bool BFS(int S) 24 { 25 int l = 0, r = 0; 26 for (int i = 0; i < 52; i ++) Flag[i] = 0; 27 q[0] = S, Flag[S] = 1; 28 while (l <= r) 29 { 30 int z = q[l ++]; 31 for (int d = 0; d < 52; d ++) 32 { 33 if (!Map[z][d]) continue ; 34 if (d == S) return 1; 35 if (Flag[d]) continue; 36 q[++ r] = d, Flag[d] = 1; 37 } 38 } 39 return 0; 40 } 41 42 int main() 43 { 44 #ifndef ONLINE_JUDGE 45 freopen("3953.in", "r", stdin); 46 freopen("3953.out", "w", stdout); 47 #endif 48 49 scanf("%d", &n); 50 for (int i = 0; i < n; i ++) 51 { 52 scanf("%s", s); 53 for (int j = 0; j < 6; j += 2) 54 for (int k = j + 2; k < 8; k += 2) 55 { 56 int a = get(s[j], s[j + 1]), b = get(s[k], s[k + 1]); 57 if ((!~a) || (!~b)) continue ; 58 Map[a][b ^ 1] = 1; 59 Map[b][a ^ 1] = 1; 60 } 61 } 62 bool ok = 0; 63 for (int i = 0; !ok && i < 52; i ++) 64 ok = BFS(i); 65 puts(ok ? "unbounded" : "bounded"); 66 67 #ifndef ONLINE_JUDGE 68 fclose(stdin); 69 fclose(stdout); 70 #endif 71 return 0; 72 }