蓝桥杯2020 E:七段码
题解
正规解法是 dfs + 并查集,首先用 dfs 将其所有的情况枚举出来,再用并查集来判断是否在一个连通块上。
许多小伙伴计算的答案为76,主要是判断连通块这方面有问题,倘若不用并查集,直接枚举一条边是否和其余剩下的边相连,是就成立,不是就可以直接退出了,但是有一个问题是例如两个连通块的时候你上述的判断也是成立的,但是不处于同一个连通块中,所以不应该加上去。
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 const int MAXN = 25; 6 int n = 7, ans = 0, path[MAXN], f[MAXN][MAXN], father[MAXN]; 7 8 //查找 x 的祖先节点 9 int find(int x) 10 { 11 if (x != father[x]) { //路径压缩 12 return father[x] = find(father[x]); 13 } 14 return father[x]; 15 } 16 17 void dfs(int u, int p, int m) 18 { 19 if (u == m) { 20 //初始化操作 21 for (int i = 1; i < MAXN; ++i) { 22 father[i] = i; 23 } 24 //集合合并 25 for (int i = 0; i < m; ++i) { 26 for (int j = i + 1; j < m; ++j) { 27 //存在边相连 28 if (f[path[i]][path[j]] == 1) { 29 //path[i] 和 path[j] 合并成一个集合 30 father[find(path[i])] = find(father[path[j]]); 31 } 32 } 33 } 34 //查找最终是否为一个集合 35 bool flag = false; 36 for (int i = 0; i < m - 1; ++i) { 37 if (find(path[i]) != find(path[i + 1])) { 38 flag = true; 39 break; 40 } 41 } 42 43 if (!flag) { 44 ++ans; 45 } 46 return ; 47 } 48 for (int i = p; i <= n; ++i) { 49 path[u] = i; 50 dfs(u + 1, i + 1, m); 51 } 52 } 53 54 int main() 55 { 56 memset(f, 0, sizeof(f)); 57 f[1][2] = f[2][1] = 1; 58 f[1][6] = f[6][1] = 1; 59 f[2][7] = f[7][2] = 1; 60 f[6][7] = f[7][6] = 1; 61 f[7][3] = f[3][7] = 1; 62 f[7][5] = f[5][7] = 1; 63 f[2][3] = f[3][2] = 1; 64 f[3][4] = f[4][3] = 1; 65 f[4][5] = f[5][4] = 1; 66 f[5][6] = f[6][5] = 1; 67 for (int i = 1; i <= n; ++i) { 68 dfs(0, 1, i); 69 } 70 cout << ans << endl; 71 return 0; 72 }
但是当时还是没有做出来/(ㄒoㄒ)/~~哭鼻子。