问题描述
有一群学生。他们中的一些人可能互相认识,而另一些人则不认识。例如,A和B互相认识,B和C互相认识。但这并不意味着A和C相互认识。
现在给你们所有互相认识的学生。你的任务是把学生分成两组,这样同一组的任何两个学生都不认识对方。如果这个目标可以实现,那就把他们安排在双人间。只有认识的学生才能住在同一个房间里。
计算可以安排到这些双人间的最大对数。
输入
对于每个数据集:
第一行给出两个整数n和m。接下来的m行给出这样的对。
输出
如果这些学生不能分成两组,请打印“否”。否则,打印在这些房间中可以安排的最大对。
bfs染色判定是否为二分图+最大匹配
#include <queue>
#include <cstring>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
const int N=200+5;
int head[N],mt[N];
int col[N],tot;
struct Edge{int to,nex;}edge[N*N/2];
void add(int from,int to)
{
edge[++tot]=(Edge){to,head[from]};head[from]=tot;
}
queue<int>q;
int istwo()
{
while(!q.empty())
q.pop();
m(col,0);
col[1]=1,q.push(1);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to;
if(!col[y])
{
col[y]=col[x]==1?2:1; //相邻没被染色。染y与x不相同的颜色。
q.push(y);
}
else if(col[y]==col[x]) //被染色。与相邻染色相同则不是二分图。
return 0;
}
}
return 1;
}
int find_path(int x)
{
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to;
if(!col[y])
{
col[y]=1;
if(!mt[y]||find_path(mt[y]))
{
mt[y]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
m(head,0),m(mt,0);
tot=1;
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
if(!istwo())
puts("No");
else
{
int ans=0;
for(int i=1;i<=n;i++)
{
m(col,0);
if(find_path(i))
ans++;
}
printf("%d\n",ans);
}
}
}