历届试题 分考场
时间限制:1.0s 内存限制:256.0MB

问题描述
  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.(蓝桥杯)分考场(无向图染色)https://blog.csdn.net/zxwsbg/article/details/80376847
2.蓝桥杯_ 历届试题 分考场 (图的着色问题)
https://blog.csdn.net/li1615882553/article/details/79694958
3.蓝桥杯 历届试题 分考场 (DFS)
https://blog.csdn.net/qq_41923622/article/details/80405277
4.蓝桥杯历届试题分考场-回溯搜索最值
https://blog.csdn.net/memeda1141/article/details/80301201

思路:
总体思路是:依次深搜每个学生,找到他们能去的房间,找不到能去的房间就开一个新房间,直到所有学生安排完成,得出结果ans。

通过回溯遍历出所有可能的安排情况,找出其中最小的ans。

剪枝那一步很关键,但不是很好弄懂,建议开始理解的时候先跳过。

这次尝试写出了第一个样例的过程伪代码,建议配合源代码一起分析。
耐心点看,应该会有所领悟的。

样例1过程伪代码:

int main()
{dfs(1,0) //判断第1个同学  目前房间数为0return 0;
}dfs1(x=1,sum=0)//判断第1个同学  目前房间数为0
{if(sum>=ans)   //此时ans为无穷大 ,判断为false,本伪代码没有涉及到剪枝,但剪枝非常重要 if(x==n+1)        //此时n=5, 判断为falsefor(i=1;i<=sum;)//此时sum=0,判断为false f[sum+1][++c[sum+1]] = x;  //开设第一房间 一号房间的第一个人为x(x=1) //dfs(x+1,sum+1);     dfs(1+1,0+1)/*********************************第2层DFS内部****************************************/  dfs2(x=2,sum=1)//判断第2个同学  目前房间数为1     //dfs(1+1,0+1){for(i=1;i<=sum;i++){int len=c[1]=1;for(int j=1;j<=len;j++){if(!a[x][f[i][j]])//房间i的第j个人与x是否有关系//这里是a[2][f[1][1]]=a[2][1]=1,故房间i的第j个人与x有关系//此时k就不会++; }if(k==len)//k<len,房间i里有人和当前学生x有关联,false}f[sum+1][++c[sum+1]] = x;  //开设房间2,房间2人数c[1+1],由0变成1 //dfs(x+1,sum+1);    dfs(2+1,1+1)/*********************************第3层DFS内部****************************************/          dfs3(x=3,sum=2)//判断第3名同学,当前房间数为2{for(i=1;i<=sum;i++)//对房间进行遍历{int len=c[1]=1;//当前房间人数为1 for(int j=1;j<=len;j++){if(!a[x][f[i][j]])//判断当前x(x=3)号同学和房间i的同学是否有关联//这里 a[3][f[1][1]]=a[3][1]=1,所以有关联 } if(k==len)//false   //当i=2时,对房间2进行判断 {int len=c[2]=1;//房间2的人数为1for(int j=1;j<=len;j++){if(!a[x][f[i][j]])//判断x=3号同学和房间i中的第j名同学的关系//当前 a[3][f[2][1]]=a[3][2]=1} if(k==len)//k<len ,false             } }f[sum+1][++c[sum+1]] = x; //开设房间3,房间3的人数由0变1 //dfs(x+1,sum+1); dfs(3+1,2+1)/*********************************第4层DFS内部****************************************/              dfs4(x=4,sum=3)//对第4名同学进行判断,此时房间有三个{for(i=1;i<=sum;i++)//对已有的三个房间遍历,发现4号同学与三个房间的三名同学都认识f[sum+1][++c[sum+1]] = x;  //开设房间4 //dfs(x+1,sum+1);dfs(4+1,3+1)/*********************************第5层DFS内部****************************************/                                          dfs5(x=5,sum=4)//对第五名同学进行判断,此时房间有4个{for(int i=1;i<=sum;i++)//对前四间房间进行遍历{int len=c[1]=1;//一号房间一个人for(int j=1;j<len;j++){if(!a[x][f[i][j]])//判断x=5号同学和第i个房间第j个人的关系//这里时第一个房间第一个人,a[x][f[i][j]=a[5][f[1][1]]=a[5][1]=0//故他俩不认识,k++ } if(k==len)//k==len==1{f[i][++c[i]]=x;//第i个(第一个)房间 的人数++//f[1][2]=5,一号房间第二个人是五号学生//dfs(x+1,sum); dfs(5+1,4)此时的房间数就不用增加了 /*********************************第6层DFS内部****************************************/                                                    dfs6(x=6,sum=4){if(x==n+1)//此时x==n+1==6{ans=min(ans,sum)//ans的初始值很大,此时sum=4//故ans=4;return; }   }/*********************************第6层DFS内部****************************************/                                                        c[i]--; //回溯 }} } /*********************************第5层DFS内部****************************************/                            c[sum+1]--; //回溯}/*********************************第4层DFS内部****************************************/            c[sum+1]--; //回溯}  /*********************************第3层DFS内部****************************************/   c[sum+1]--; //回溯} /*********************************第2层DFS内部****************************************/  c[sum+1]--; //回溯
}

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=105;
int n,m;    //n名学生  m种关系
int a[N][N];//用于表示任意两名同学间的联系
int f[N][N];//用于表示第i个房间的第j个人是谁
int c[N];   //用于记录当前房间有多少人
int ans=N; //ans为所需最少房间数 ,开始时将其标记成较大数(人数最多100人)
void dfs(int x,int sum)
{if(sum>=ans)//剪枝,很关键,能节省大量时间,ans开始标记成较大数对此语句无影响 {return;}if(x==n+1)//所有同学安排好房间了{ans=min(ans,sum);//判断已有的ans和当前sum谁更小 return;} for(int i=1;i<=sum;i++){int len=c[i],k=0;//len和c[i]为当前房间人数 for(int j=1;j<=c[i];j++){if(!a[x][f[i][j]])//不认识,k就++ k++;}if(k==len)//当前房间所有人都不认识x时为true,只要有一个人认识x就会有k<len {f[i][++c[i]]=x;//房间i的人数c[i]++,标号为x号学生 dfs(x+1,sum);//继续深搜,判断下一个学生 ,房间数不用增加 --c[i]; //回溯回来,要把当前所在房间数减一      }}sum++;//当前同学没有房间能去,新开一个房间 f[sum][++c[sum]]=x;//房间sum的第c[sum]为x,c[sum]由0变1dfs(x+1,sum);//继续深搜,判断下一个学生,sum是已经增加1的房间数 --c[sum]; //回溯回来,要把当前所在房间数减一
}
int main()
{cin>>n>>m; //n名学生  m种认识状态 for(int i=0;i<m;i++){int x,y;cin>>x>>y;            //读入关系 a[x][y]=a[y][x]=true;  //x,y互相认识建立联系 }dfs(1,0);//从第一个人,房间数为0开始搜索 cout<<ans<<endl;return 0;
}

在挂一个学长的代码(这题最早给我启发的代码)

#include<bits/stdc++.h>
using namespace std;
bool mp[110][110];
int tuan[110][110];
int cnt=0, ans=INT_MAX;
int n, m;bool check(int p, int b){int sz=tuan[b][0];for(int i=1; i<=sz; i++){if(!mp[tuan[b][i]][p]) return false;} return true;
}void dfs(int p){if(p==n+1){ans=min(ans, cnt);return;}  if(cnt>=ans) return;for(int i=1; i<=cnt; i++){if(check(p, i)){tuan[i][++tuan[i][0]]=p;dfs(p+1);tuan[i][0]--;}}++cnt;tuan[cnt][++tuan[cnt][0]]=p;dfs(p+1);tuan[cnt][0]=0;cnt--;return;
}int main(){scanf("%d%d", &n, &m);memset(mp, true, sizeof mp);memset(tuan, 0, sizeof tuan);for(int i=1; i<=m; i++){int u, v;scanf("%d%d", &u, &v);mp[u][v]=mp[v][u]=false; }dfs(1);printf("%d\n", ans);return 0;
}

【蓝桥】 历届试题 分考场(DFS,回溯,剪枝,无向图染色问题)相关推荐

  1. 历届试题 分考场(DFS,染色问题)

    历届试题 分考场 时间限制:1.0s 内存限制:256.0MB 问题描述 n个人参加某项特殊考试. 为了公平,要求任何两个认识的人不能分在同一个考场. 求是少需要分几个考场才能满足条件. 输入格式 第 ...

  2. 蓝桥杯 历届试题 分考场 (DFS)-----C语言—菜鸟级

    问题 1874: [蓝桥杯][2017年第八届真题]分考场 时间限制: 1Sec 内存限制: 128MB 提交: 62 解决: 12 题目描述 n个人参加某项特殊考试. 为了公平,要求任何两个认识的人 ...

  3. 蓝桥杯 历届试题 分考场(DFS+枚举)

    传送门 题目描述 n个人参加某项特殊考试. 为了公平,要求任何两个认识的人不能分在同一个考场. 求是少需要分几个考场才能满足条件. 输入 第一行,一个整数n(1<n<100),表示参加考试 ...

  4. 蓝桥杯 历届试题 分考场(C语言)

    分考场 问题描述 n个人参加某项特殊考试. 为了公平,要求任何两个认识的人不能分在同一个考场. 求是少需要分几个考场才能满足条件. 输入格式 第一行,一个整数n(1<n<100),表示参加 ...

  5. 蓝桥杯c语言试题幸运数,蓝桥杯  历届试题 幸运数  dfs

    时间限制:1.0s   内存限制:256.0MB 问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的"筛法"生成 . 首先从1开始写出自然数1,2,3,4,5,6,. ...

  6. java 蓝桥杯历届试题 分糖果(题解)

    试题 历届试题 分糖果 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 有n个小朋友围坐成一圈.老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏: 每个小朋友都把自己的糖果分一半 ...

  7. 【蓝桥杯】历届试题 分糖果

    历届试题 分糖果   时间限制:1.0s   内存限制:256.0MB 问题描述 有n个小朋友围坐成一圈.老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏: 每个小朋友都把自己的糖果分一半给左手边 ...

  8. 蓝桥历届试题 高僧斗法

    蓝桥历届试题 高僧斗法 高僧斗法 题目 思路 代码 高僧斗法 题目 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 古时丧葬活动中经常请高僧做法事.仪式结束后,有时会有"高 ...

  9. 蓝桥 历届试题 核桃的数量

    历届试题 核桃的数量 时间限制:1.0s   内存限制:256.0MB 问题描述 小张是软件项目经理,他带领3个开发组.工期紧,今天都在加班呢.为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑). ...

最新文章

  1. 微信推送模板消息的PHP代码整理
  2. 图解一次Linux挂载操作和mount命令基本用法
  3. 史上最坑的证书报错解决方法:Code=3000 未找到应用程序的“aps-environment”的权利字符串
  4. 交叉编译mysql客户端libmysql
  5. python接口自动化接口依赖_Python接口自动化之mock模块简单使用
  6. windows下cmd命令提示符下让程序后台运行命令
  7. 国家开放大学2021春1044合同法题目
  8. Java内功修炼系列一工厂模式
  9. java aopalliance-1.0.jar这个包是做什么用的?
  10. java操作oracle数据_Java连接Oracle数据库操作
  11. python从入门到实践答案第四章_《python从入门到实践》--第四章基本操作列表 重点及课后练习...
  12. 六企业级开源仓库nexus3实战应用–使用nexus3配置yum私有仓库
  13. iOS数据持久化(二)SQLite
  14. 中信建投软件测试,中信建投笔试经验-范例
  15. jupyter notebook magic %time %%time 告诉你运行时长
  16. 盖世神器PowerPro使用视频教程-1. 程序的安装概述
  17. unity学习之路—飞机大战
  18. abb机器人指令手册_ABB机器人速度设置
  19. Plant Simulation之数字孪生
  20. vue.js中created()与activated()

热门文章

  1. 在线原型设计工具推荐
  2. Linux 系统黑洞 /dev/null
  3. web 报表轻松实现数据异常预警功能
  4. JQuery Mobile(书籍分类检索)
  5. iframe跨端口报错 :Blocked a frame with origin
  6. LC117A泛海微马达驱动IC SOP-8
  7. XWPFDocument 创建Word并且生成目录结构
  8. ILOG 甘特图 ActivityTable 去掉自动属性及其他
  9. Python 猜数字小游戏,3次机会
  10. 高通导航器软件开发包使用指南(13)