【训练题】二分图判定
2016-07-09 15:09
381 查看
【问题描述】
对于无向图 G=(V,E),如果可以把结点集分成不相交的部分,即 X和 Y=V-X,使得每条边的其中一个端点在 X 中,另一个在 Y 中,则称 G 为二分图(bipartite graph)。二分图的另一种等价说法是,可以把每个结点着以黑色和白色之一,使得每条边的两个端点颜色不同,所以黑白染色法这就是判定二分图的基本算法。不难发现,非连通图是二分图当且仅当每个连通分量都是二分图。比如下面的问题就是典型的二分图判定问题:
期末考试的时候,老师要把全班学生分在两个考场。老师在分考场的时候要考虑尽量避免把相互之间比较熟悉的同学分在同一的考场,因为他们可能会联合起来作弊。现在老师统计了同学们相互之间熟悉情况,他想知道能否合理地分考场,将所有相互熟悉的同学分在不同的考场。
【输入格式】
输入第一行是一个整数T,表示有T(T<=20)组测试数据。接下来每一组测试数据包括两个部分。第一部分只有一行,有两个整数n,m(2<=n<=1000,m<=n*(n-1)/2)。分别表示学生的人数和老师掌握的学生之间熟悉关系个数。第二部分有m行,每行有两个整数a,b。表示学生a和学生b相互认识,即有可能联合起来作弊。a和b分别表示学生的标号,且从1开始(1<=a,b<=n)。
【输出格式】
对于每组测试数据,输出按照样例的格式。第一行表示是第几组数据。如果能把所有学生分在两个考场,且不可能发生作弊行为,第二行输出”Yes”,否则输出”No”。
【输入样例】
【输出样例】
【数据范围】
T<=20
2<=n<=1000,m<=n*(n-1)/2
思路:
该题在BFS的同时对一条边的两个结点进行涂色,当矛盾时即可跳出。
对于无向图 G=(V,E),如果可以把结点集分成不相交的部分,即 X和 Y=V-X,使得每条边的其中一个端点在 X 中,另一个在 Y 中,则称 G 为二分图(bipartite graph)。二分图的另一种等价说法是,可以把每个结点着以黑色和白色之一,使得每条边的两个端点颜色不同,所以黑白染色法这就是判定二分图的基本算法。不难发现,非连通图是二分图当且仅当每个连通分量都是二分图。比如下面的问题就是典型的二分图判定问题:
期末考试的时候,老师要把全班学生分在两个考场。老师在分考场的时候要考虑尽量避免把相互之间比较熟悉的同学分在同一的考场,因为他们可能会联合起来作弊。现在老师统计了同学们相互之间熟悉情况,他想知道能否合理地分考场,将所有相互熟悉的同学分在不同的考场。
【输入格式】
输入第一行是一个整数T,表示有T(T<=20)组测试数据。接下来每一组测试数据包括两个部分。第一部分只有一行,有两个整数n,m(2<=n<=1000,m<=n*(n-1)/2)。分别表示学生的人数和老师掌握的学生之间熟悉关系个数。第二部分有m行,每行有两个整数a,b。表示学生a和学生b相互认识,即有可能联合起来作弊。a和b分别表示学生的标号,且从1开始(1<=a,b<=n)。
【输出格式】
对于每组测试数据,输出按照样例的格式。第一行表示是第几组数据。如果能把所有学生分在两个考场,且不可能发生作弊行为,第二行输出”Yes”,否则输出”No”。
【输入样例】
1 7 6 1 2 1 3 2 4 2 5 3 6 3 7
【输出样例】
case 1: Yes
【数据范围】
T<=20
2<=n<=1000,m<=n*(n-1)/2
思路:
该题在BFS的同时对一条边的两个结点进行涂色,当矛盾时即可跳出。
/* Name: Bipartite_Graph Copyright: Twitter & Instagram @stevebieberjr Author: @stevebieberjr Date: 09-07-16 15:35 */ #include<cstdio> #include<queue> #include<cstring> #include<vector> #define maxn 1005 using namespace std; int color[maxn]; //color: 0未访问 1颜色为1 2颜色为2 int T,n,m,ok; //ok: 是否有某一条边相邻两个结点颜色相同 vector<int>g[maxn]; void BFS(int z) { queue<int>q; color[z]=1; //假设结点z的颜色为1 q.push(z); while(!q.empty()) { int i=q.front(); q.pop(); for(int k=0;k<g[i].size();k++) { int j=g[i][k]; if(color[i]==color[j] && color[j]!=0) ok=0; //跟i相连的结点颜色相同并且已访问过,ok=0 if(color[j]==0) { q.push(j); color[j]=3-color[i]; //给j结点涂上与i结点相反的颜色 } } if(ok==0) break; } } int main() { //freopen("in.txt","r",stdin); scanf("%d",&T); for(int k=1;k<=T;k++) { memset(color,0,sizeof(color)); for(int i=1;i<=n;i++) { g[i].clear(); } scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); g[x].push_back(y); g[y].push_back(x); //无向图的存储 } ok=1; for(int i=1;i<=n;i++) { if(color[i]==0) BFS(i); //确保遍历到每个连通分量 } printf("case %d:\n",k); if(ok) printf("Yes\n"); else printf("No\n"); } return 0; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 如何组织构建多文件 C 语言程序(二)
- 关于指针的一些事情
- 如何写好 C main 函数
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- Lua中调用C++函数示例
- Lua和C语言的交互详解
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析