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