http://acm.hdu.edu.cn/showproblem.php?pid=2444
有些人互相認識,但認識不具有傳遞性,比如A認識B,B認識C,不代表A認識C。給出所有認識關係,問能不能分成兩個班,每個班裏的人互相不認識。如果可以,一間宿舍可以住兩個人,這兩個人必須互相認識,問最多分配多少宿舍。
二分圖判斷和最大匹配。
分成不同的班相當於能不能構成二分圖,分宿舍就是最大匹配。
注意能構成二分圖不代表最大匹配是n/2。(n爲點的個數)
關於二分圖判斷和最匹配的講解在我的另一篇博客。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#define INF 0x3f3f3f3f
#define me(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=210;
int n,m,line[N][N],ans[N],color[N];
bool used[N];
bool dfs(int u,int c)
{
color[u]=c;
for(int i=1;i<=n;i++)
{
if(!line[u][i])
continue;
if(!color[i])
{
if(dfs(i,-c))
continue;
return false;
}
else
if(color[i]+color[u])//相同顏色說明不能構成二分圖
return false;//不同顏色就是一個-1,一個1,相加爲0,爲假,所以不會執行下面的return
}
return true;
}
bool find(int x)
{
for(int i=1;i<=n;i++)
if(line[x][i]&&!used[i])
{
used[i]=1;
if(!ans[i]||find(ans[i]))
{
ans[i]=x;
return 1;
}
}
return 0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
me(line,0);
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
line[u][v]=1;//如果在這裏建雙向邊,那麼cnt即最大匹配會是兩倍,匹配裏的每一條邊被算了兩邊
}
me(color,0);
bool f=1;
for(int i=1;i<=n&&f;i++)
{
if(!color[i]&&!dfs(i,1))
f=0;
}
if(!f)
printf("No\n");
else
{
me(ans,0);//別忘在這裏初始化
int cnt=0;
for(int i=1;i<=n;i++)
{
me(used,0);
if(color[i]&&find(i))
cnt++;
}
printf("%d\n",cnt);
}
}
}