题目:
输入输出:
分析:
此题使用深搜来解决,从第一个人开始逐一的分配教室,分配教室的方案如下:遍历已经存在的教室,然后再遍历教室中的所有人,查看是否存在某一个人与当前要被分配教室的人认识,如果此教室中没有认识的人,那么我们可以将当前的人分配到这个教室中,当然也可以选择不分配到当前的教室,因为分配到当前的教室可能不是最优的选择,此时就要用到回溯,回溯的目的是为了寻找最优的解决方案,当遍历当前存在的所有教室之后,还有一种策略是将当前的人分配到一个新的教室,再搜索这一种情况即可,下述代码中有详细的解释。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 105;
int mat[MAXN][MAXN]; //mat[i][j]代表决定i和j之间是否认识
int cnt[MAXN]; //cnt[i]表示第i个教室的人数
int room[MAXN][MAXN]; //room[i][j]代表第i个教室中第j个人的编号
int n,m,ans;
bool flag;
void Dfs(int person,int num) //person表示待分配的人 num表示当前教室数量
{
if(num >= ans) return; //剪枝 如果当前的教室数量大于ans 说明当前的选择肯定不是最优的
if(person > n) //如果person大于n 说明已经分配完了n个人 此时结果与ans相比较 取最优
{
ans = min(ans,num);
return;
}
for(int i=0;i<num;++i)
{
flag = false;
int allPep = cnt[i];
for(int j=1;j<=allPep;++j)
if(mat[person][room[i][j]])
{
flag=true; //如果person和此教室中的任意一个人是朋友 则不满足条件
break;
}
if(!flag)
{
cnt[i]++; //表示person这个人加入到i教室中
room[i][cnt[i]] = person;
Dfs(person+1,num);
cnt[i]--; //回溯操作 因为person加入到当前的教室可能不是最优的
}
}
cnt[num]++; //表示上述可能没有满足教室分配的最优条件 那就重新开一个新教室
room[num][cnt[num]] = person;
Dfs(person+1,num+1);
cnt[num]--; //回溯 此处表示上一次的教室分配可能不是最优
}
int main()
{
int a,b;
ans = INF;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d%d",&a,&b);
mat[a][b] = 1;
mat[b][a] = 1;
}
Dfs(1,0);
printf("%d\n",ans);
return 0;
}