题目链接:传送门(点我)
分析:可否贪心,不可,如果枚举每个人,如果发现一个队伍里面和他不认识就放进去,可否是最优解?不一定。也许放后面情况更优?对于这种关系不好理清,我选择枚举。
其实DFS就是一种层数不定的枚举。
搜索就是产生解答树的过程,而回溯是回溯当前改变的状态。也就是回到改变之前的状态 可以参考我这个题的题解。传送门(点我)
那么如果枚举的话,对于一个人,他可能有几种状态。
- 加入某个房间
- 自己新开一个房间
于是解答树应该按照这种逻辑展开
设计dfs函数时,每一层dfs就是一种状态,而全局变量room是为了避免每层dfs里面都来记录room状态浪费空间,所以回溯的时候对全局变量room操作即可。
关于剪枝:由于我们知道,深度优先搜索的解答树是 深度优先, 也就是说,当我们第一次找到一种方案,之后的如果比前面方案情况更差(房间数更多),我们就不需要对那棵树(情况)进行展开继续下去了。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 105
int n,m,a,b,res=0x7fffffff;
bool relation[MAXN][MAXN];//关系,是否认识
vector<int>room[MAXN];//存储房间当前的学生
void add(int a,int b){relation[a][b]=1;relation[b][a]=1;}
void dfs(int id,int num)
{
if(num>=res)return;
if(id>n){res=min(num,id);return;}
for(int i=1;i<=num;i++){//尝试现在有的所有房间
int flag=0;
for(int j=0;j<room[i].size();j++){//遍历房间
if(relation[id][room[i][j]]){//如果有认识的人
flag=1;
break;
}
}
if(!flag){//都不认识
room[i].push_back(id);
dfs(id+1,num);
room[i].pop_back();
}
}
//不加入房间
room[num+1].push_back(id);
dfs(id+1,num+1);
room[num+1].pop_back();
}
int main()
{
cin>>n>>m;
while(m--){
cin>>a>>b;
add(a,b);
}
dfs(1,0);
return cout<<res<<endl,0;
}