hdu2444: http://acm.hdu.edu.cn/showproblem.php?pid=2444
二分图的判断以及二分图的最大匹配
题意:
给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识;
现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多?
这道题是赤裸裸的二分图模版题,先判断是不是二分图,在用二分图最大匹配搞。
/** 二分图的判断以及二分图的最大匹配 题意: 给定n个学生,他们之间可能互相认识,首先判断能不能将这些学生分为两组,使组内学生不认识; 现想将学生两两分组,且保证每一组的学生都认识,这样分组可达到的最大组数为多? */
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
const int inf=0x3f3f3f3f;
const int MAX_=206;
int g[MAX_][MAX_];
int match[MAX_];
bool used[MAX_];
int color[MAX_];
int n,m;
/** 我一开始的做法是 直接求一边最大匹配 当每条边都有匹配的时候这个图就是二分图 事实上 这个结论是错的 */
///二分图最大匹配
int dfs(int x)
{
for(int i=1; i<=n; i++)
{
if((!used[i])&&(g[i][x]))
{
used[i]=true;
if((!match[i])||(dfs(match[i])))
{
match[i]=x;///这里 我不明白为什么不是
///match[x]=i
///事实上这里跟增广路有关
///增光路起点与终点都在“i”上
return 1;
}
}
}
return 0;
}
///二分图判定
int dfs_(int x,int color_)
{
color[x]=color_;
for(int i=1; i<=n; i++)
{
if(g[i][x]&&(color[i]==color_))///如果染色过
return 0;
if(g[i][x]&&(color[i]==-1))///如果还没有染色过
if(!dfs_(i,!color_))
return 0;
}
return 1;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in1.txt","r",stdin);
#endif // ONLINE_JUDGE
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(g,0,sizeof(g));
for(int i=0; i<m; i++)
{
int num1,num2;
scanf("%d%d",&num1,&num2);
g[num1][num2]=1;
g[num2][num1]=1;
}
int ans=0;
///WA fill(match,match+n,0);
memset(match,0,sizeof(match));
for(int i=1; i<=n; i++)
{
memset(used,false,sizeof(used));
///if(match[i]==0&&dfs(i))
///为什么这个是错的 当前的匹配边即使不是0
///也可能找到增广路 这样的条件使这样程序没有重新匹配的机会
if(dfs(i))
ans++;
}
bool judge=true;
memset(color,-1,sizeof(color));
for(int i=1; i<=n; i++)
{
if(color[i]==-1&&dfs_(i,0)==0)
///还没有染过色 就去染色 染不了 失败 不是二分图
judge=false;
}
if(!judge)
{
puts("No");
}
else printf("%d\n",ans/2);
}
return 0;
}