您的位置:首页 > 编程语言 > C语言/C++

【训练题】二分图判定

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”。

【输入样例】

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息