历届试题 分考场
问题描述
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 <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 }
作者:你的雷哥
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!