思路:
step1:邻接表建图,相邻为1,不相邻为0,题目就等价为在图中求连通子图的个数。
step2:深度搜索每条边,并存储下来。
step3:对选择的边用并查集保存下来,然后看father[i] == i的个数,等于1,表示连通,否则表示不连通。
易错点:
1:建图时别忘了[5][6] 和[2][3] 也是相邻的
2:dfs如果需要存储搜索的结果,用一个数组的0和1来保存就行
3:选子序列的dfs代码为:
flag[i] = 1;
dfs(i + 1);
flag[i] = 0;
dfs(i + 1);
4:并查集的使用
#include <bits/stdc++.h>
using namespace std;
void creat();
void dfs(int i);
int find(int i); //查找并查集中的根
int mp[8][8]; //图
int flag[8]; //标志,1表示该灯亮
int father[8];
int result = 0;
int main(){
// //建图
creat();
// //深搜
dfs(1);
cout << result << endl;
return 0;
}
void creat(){
for (int i = 1; i < 8; ++i){
for (int j = 1; j < 8; ++j){
mp[i][j] = 0;
}
}
mp[1][2] = mp[1][6] = 1;
mp[2][1] = mp[2][7] = mp[2][3] = 1;
mp[3][4] = mp[3][7] = mp[3][2] = 1;
mp[4][3] = mp[4][5] = 1;
mp[5][4] = mp[5][7] = mp[5][6] = 1;
mp[6][1] = mp[6][7] = mp[6][5] = 1;
mp[7][2] = mp[7][3] = mp[7][5] = mp[7][6] = 1;
}
void dfs(int i){
if (i == 8){
for (int m = 1; m <= 7; ++m){ //初始值要注意,都是i,而不是0!!!
father[m] = m;
}
for (int i = 1; i <= 7; ++i){ //构造并查集
for (int j = 1; j <= 7; ++j){
if (mp[i][j] && flag[i] && flag[j]){
//两个集合的合并,操作的是根的下标!!!
int x = find(i);
int y = find(j);
if (x != y) {
father[x] = y;
}
}
}
}
int cnt = 0; //根的个数
for (int i = 1; i<= 7; ++i){
if (flag[i] && father[i] == i) cnt++; //应该是father,而不是find()!!!
}
if (cnt == 1) result++;
return ;
}
flag[i] = 1;
dfs(i + 1);
flag[i] = 0;
dfs(i + 1); //这一句不能少,这种情况为该灯熄灭的情况!!!
}
int find(int i){
if(father[i] == i) return i;
return find(father[i]);
}
//答案是80