蓝桥杯 试题 历届试题 分考场 dfs+回溯
问题描述
n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
输入格式
第一行,一个整数n(1<n<100),表示参加考试的人数。
第二行,一个整数m,表示接下来有m行数据
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
第二行,一个整数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
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
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5
- 解题思路:依次安排学生,尝试所有可能的考场(满足不认识考场所有人或者将该学生放入新考场) + 回溯,取所有可能最小考场。(加上简单判断剪枝)
- 解题代码:
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 5 const int Max_N = 100; 6 const int INF = 100000; 7 8 //输入 9 int n,m; 10 11 bool acq[Max_N+1][Max_N+1] = {false,};//acq[i][j]=true i与j考生认识 12 vector<int> room[Max_N]; //考场 13 int res = INF; //保存最优解 14 15 //id:学生编号 num:当前考场最大编号 16 void dfs( int id, int num ) 17 { 18 if( num>=res ){ 19 return; //剪枝 20 } 21 if( id==n+1 ){//安排完所有学生 22 res = num; //大于的都被剪枝了 23 return; 24 } 25 26 for( int i=0; i<num; i++ ) 27 { 28 bool flag = false; 29 for( int j=0; j<room[i].size(); j++ ) 30 { 31 int id_ = room[i][j]; 32 if( acq[id][id_] ){ 33 flag = true; 34 break; 35 } 36 } 37 if( !flag ) 38 {//满足条件 不认识该考场所有学生 39 room[i].push_back( id ); 40 dfs( id+1, num ); 41 room[i].pop_back(); //回溯 42 } 43 } 44 45 //新开考场 46 room[num].push_back( id ); 47 dfs( id+1, num+1 ); 48 room[num].pop_back(); 49 } 50 51 void solve() 52 { 53 dfs( 1,0 ); 54 55 printf("%d\n",res); 56 } 57 58 int main() 59 { 60 scanf("%d%d",&n,&m); 61 while( m-- ) 62 { 63 int u,v; 64 scanf("%d%d",&u,&v); 65 acq[u][v] = acq[v][u] = true; 66 } 67 68 solve(); 69 70 return 0; 71 }