蓝桥杯 试题 历届试题 分考场 dfs+回溯

问题描述
  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
  • 解题思路:依次安排学生,尝试所有可能的考场(满足不认识考场所有人或者将该学生放入新考场) + 回溯,取所有可能最小考场。(加上简单判断剪枝)
  • 解题代码:
 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
",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 }
 
原文地址:https://www.cnblogs.com/w-like-code/p/13945922.html