题解

  正规解法是 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ㄒ)/~~哭鼻子。

内容来源于网络如有侵权请私信删除