【问题描述】 | ||
对于无向图 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,将遍历到的点进行标记,通过标记是否有矛盾情况进行判断是否为二分图。
#include<iostream>
#include<cstdio>#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1005;
int n,m,T,ok;
vector<int>a[maxn];
bool vis[maxn],c[maxn];
void init()
{
memset(vis,0,sizeof(vis));
memset(c,0,sizeof(c));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
a[i].clear();
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x].push_back(y);
a[y].push_back(x);
}
}
void bfs()
{
queue<int>q;
q.push(1);
c[1]=1;
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=0;i<a[t].size();i++)
{
int j=a[t][i];
if(vis[j]&&c[j]==c[t]) ok=0; 矛盾情况,标记为不是二分图
if(vis[j]==0)
{
q.push(j);
c[j]=1-c[t];
vis[j]=1;
}
}
if(ok==0) break;
}
}
int main()
{
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
init();
ok=1; 假定为二分图
bfs();
printf("case %d:\n",i);
if(ok) printf("Yes");
if(ok==0) printf("No");
}
return 0;
}