问题描述
n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
输入格式
第一行,一个整数n(1<n<100),表示参加考试的人数。
第二行,一个整数m,表示接下来有m行数据
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
输出格式
一行一个整数,表示最少分几个考场。
样例输入
5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
4
样例输入
5
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5
一开始以为是简单的贪心问题,可不想一直正确率40%.
最后发现还是需要采用回溯,在剪枝下深度遍历所有情况.
#include <stdio.h>
int pre[100][100]={0},pre_num[100][100]={0},min=100;
void join(int sum,int n,int m){
int i=0,j;
for(i=0;i<sum;i++){
if(pre[m][i]==1){
pre_num[n][i]=1;
}
}
}
void DF(int a,int k,int num){
if(num>=min)return; //大于以找到的最小考场数,直接忽略
int j_1,i,cp[100]={0};
//遍历所有可能进入的考场
for(j_1=0;j_1<num;j_1++){
if(pre_num[j_1][k]==0){
key=1;
for(i=0;i<a;i++){ //保存要修改的状态
cp[i]=pre_num[j_1][i];
}
join(a,j_1,k);
//printf("%d-%d A试试%d加到%d中\n",num,min,k,j_1);
if(k<a)
DF(a,k+1,num);
else{
//printf("找到一种结果:%d\n",num);
if(num<min){
min=num;
}
}
//printf("%d-%d B将%d取出到%d中\n",num,min,k,j_1);
for(i=0;i<a;i++){ //还原状态
pre_num[j_1][i]=cp[i];
}
}
}
//自己建立新考场
join(a,num,k);
num++;
//printf("%d-%d C试试%d加到%d中\n",num,min,k,num);
if(k<a)
DF(a,k+1,num);
else{
//printf("找到一种结果:%d\n",num);
if(num<min){
min=num;
}
}
num--;
for(i=0;i<a;i++){
pre_num[num][i]=0;
}
}
int main(){
int a,b,i,j_1,j_2,j;
scanf("%d",&a);
scanf("%d",&b);
for(i=0;i<b;i++){
scanf("%d %d",&j_1,&j_2);
pre[j_1-1][j_2-1]=1;
pre[j_2-1][j_1-1]=1;
}
DF(a,0,0);
printf("%d\n",min);
return 0;
}