トピック:
入力と出力:
分析:
深い検索を使用して解決するために、この問題は、教室の最初の個々の割り当てから一つずつを開始し、教室の割り当て方式は下記の通りである:トラバース電流で個々があることがあるかどうかを確認するためにトラバースすべての教室の後、教室を既存の、そして人々は教室の分布を知っているこの人は知っていない場合、我々は、この教室のコースに割り当てられた人を提示することができますので、教室では、あなたが最適ではないかもしれない現在の教室に割り当てられているように、現在の教室に割り当てるしないことを選択することができますその後、私たちはバックトラックを使用する必要があり、選択し、目的をバックトラッキングすることは、最適なソリューションを見つけることです、現在存在するすべての教室を通過した後、現在の戦略は、その後、新しい教室に割り当てる人々に、この検索されています状況に、以下のコードは詳細に説明されています。
コード:
#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;
}