问题描述

  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 <bits/stdc++.h>
2 using namespace std;
3 int Amap[1001][1001];
4 int p[1001];
5 vector<int> a[1001];
6 int n,m;
7 int main()
8 {
9 cin >> n >> m;
10 int a1,a2;
11 memset(Amap,0,sizeof(Amap));
12 memset(p,0,sizeof(p));
13 for(int i=1;i<=m;i++){
14 cin >> a1 >> a2;
15 Amap[a1][a2]=1;
16 //Amap[a2][a1]=1;
17 }
18 int num=0;
19 int flag;
20 for(int i=1;i<=n;i++){
21 if(p[i]==1) continue;
22
23 // cout << i <<" ";
24 for(int j=i+1;j<=n;j++){
25 if(i==j) continue;
26 flag=0;
27 if(Amap[i][j]==0&&Amap[j][i]==0&&p[j]==0){
28
29 for(vector<int>::iterator iter=a[i].begin();iter!=a[i].end();++iter){
30 if(Amap[*iter][j]==1 || Amap[j][*iter]==1) flag=1;
31 }
32 if(flag==0){
33 a[i].push_back(j);
34 // cout << j << " ";
35 p[j]=1;
36 }
37 }
38 }
39 //cout << endl;
40 p[i]=1;
41 num++;
42
43 }
44 cout << num << endl;
45 return 0;
46 }

百度之后可以考虑使用dfs,

每新加进来一个人,都与已经开设的教室里面的人进行对比,如果找到一个教室满足,教室里面所有的人都不和新加入的人认识,那么就考虑将这个人加进来。再回溯。最后,当所有教室都不满足的时候,新增教室。参考代码如下

1 #include<iostream>
2
3 #include<vector>
4
5 using namespace std;
6
7 #define MAXN 110
8
9 #define INF 0x3f3f3f3f;
10
11 int graph[MAXN][MAXN];//建立图
12
13 int cun[MAXN][MAXN];//存储第几个教师有谁谁谁
14
15 int cnt[MAXN]={0};//记录每个教室的人数
16
17 int res=INF;//假设需要一个无穷多的教室
18
19 int n,m;//定义人数,以及认识的数目
20
21 void solve(int id,int num)//回溯搜索,id表示当前安排的是第id的同学,num表示当前安排这个id同学的时时候已经用了多少个教室
22
23 {
24
25 if(num>=res)//如果当前的教室方案已经超过以前的方案了,那么就放弃返回
26
27 return;
28
29 if(id>n)//如果说id的同学的id>n说明全部的同学都安排完了
30
31 {
32
33 res=num;//如果执行到这一步说明res一定是.>num的,所以更新一下
34
35 return;//返回
36
37 }
38
39 for(int i=0;i<num;i++)//扫描每一个已经存在的教室
40
41 {
42
43 int len=cnt[i];//取一下当前i教室的人数
44
45 int c=0;//这个变量表示当前id的同学和这个教室的同学不认识的人数
46
47 for(int j=0;j<len;j++)//扫描这个教室的每一个同学
48
49 {
50
51 if(graph[id][cun[i][j]]==0)//如果没有关系
52
53 c++;//加1
54
55 }
56
57 if(c==len)//如果全部不认识
58
59 {
60
61 cun[i][cnt[i]++]=id;//那么id同学就进入这个教室,同时这个教室的人数+1
62
63 solve(id+1,num);//那么安排下一个教室
64
65 cnt[i]--;//递归返回之后把这个同学在从这个教室分走,分到下几个教室看看
66
67 }
68
69 }
70
71 cun[num][cnt[num]++]=id;//如果全部教室都存在id认识的同学,那么就把这个同学新开个教室
72
73 solve(id+1,num+1);//递归下一个同学并且当前的教室数目+!
74
75 cnt[num]--;//返回后移除这个同学看下上一个同学有没有其他的选择
76
77 }
78
79 int main()
80
81 {
82
83 cin>>n>>m;
84
85 for(int i=0;i<m;i++)
86
87 {
88
89 int a,b;
90
91 cin>>a>>b;
92
93 graph[a][b]=1;
94
95 graph[b][a]=1;//如果两个人认识的话就可以标记成1,c++在数组创建 的时候已经快速初始化
96
97 }
98
99 solve(1,0);//进入回溯更新最小的教室数目
100
101 cout<<res;//输入所有可能中的最小的答案
102
103 }

 

作者:你的雷哥

本文版权归作者所有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。