poj 3692二分图……本人太弱,才明白过来。

来源:互联网 发布:人工智能贴吧 编辑:程序博客网 时间:2024/06/06 20:08
首先说明一下,由两个完全子图连接而成的图的补图一定是二分图。
然后是这个题了。
本来想直接用二分,结果一看不对啊,匈牙利算法并不符合题意啊。
那怎么办……
方法:
题意给的图是两个完全子图连接而成的图,
那么我们先取它的补图。补图上凡是两点之间有边的,都是原图上相互间没有关系的(对应于题意就是两个人不认识的)。
那么我们选点(也就是选人)就不能选在相同边上的两个点,对吧?(因为他们不认识啊。)
又一想,这不是点独立集吗?就是求原图的补图的最大点独立集就是了。
那怎么求?有定理可以用:最大点独立集点数+最大匹配数=总顶点数。
然后就可以AC啦~
这边我用的是很基础的dfs匈牙利~
AC代码:
注意Boy和Girl是有顺序的,for循环别弄反了。
#include <iostream>#include <string>#include <cstring>#include <cstdio>using namespace std;const int maxn=4e3+10;int B,G,M;bool mp[maxn][maxn];bool used[maxn];int mate[maxn];bool Findm(int x){    for(int i=1;i<=B;i++)    {        if(!used[i]&&mp[x][i])        {            used[i]=1;            if(!mate[i]||Findm(mate[i]))            {                mate[i]=x;                 return 1;            }        }    }    return 0;}int main(){    int cas=1;    while(scanf("%d%d%d",&G,&B,&M)==3&&B&&G&&M)    {        for(int i=1;i<=maxn;i++)//本来是初始化为0的,现在都初始化为1            for(int j=1;j<=maxn;j++)                mp[i][j]=1;        for(int i=1;i<=M;i++)        {            int t1,t2;            scanf("%d%d",&t1,&t2);            mp[t1][t2]=0;//逆着建图就好了。        }        int temp=0;        memset(mate,0,sizeof(mate));        for(int i=1;i<=G;i++)//题目描述的是哪个Girl认识哪个Boy而不是Boy认识Girl,所以for循环别反了,WA了几发……        {            memset(used,0,sizeof(used));            temp+=Findm(i);        }        printf("Case %d: %d\n",cas++,B+G-temp);    }}