POJ 3692 Kindergarten(二分图最大团)

来源:互联网 发布:java迷宫小游戏设计 编辑:程序博客网 时间:2024/05/16 18:51

题意:

有G个女孩,B个男孩。女孩彼此互相认识,男孩也彼此互相认识。有M对男孩和女孩是认识的。分别是(g1,b1),.....(gm,bm)。

现在老师要在这G+B个小孩中挑出一些人,条件是这些人都互相认识。问最多可以挑出多少人。

 

思路:

女孩之间互相认识,男孩之间互相认识,所以我们可以将连边定义为:不认识。即:若两个节点之间有连边,则两个节点互不认识。

故题意即为选出最多的点使得这些点任意两点之间没有连边。即选最少的点覆盖所有边。(二分图最大独立集/二分图最小点覆盖)


二分图的最大团

定义:对于一般图来说,团是一个顶点集合,且由该顶点集合诱导的子图是一个完全图,简单说,就是选出一些顶点,这些顶点两两之间都有边。最大团就是使得选出的这个顶点集合最大。对于二分图来说,我们默认为左边的所有点之间都有边,右边的所有顶点之间都有边。那么,实际上,我们是要在左边找到一个顶点子集X,在右边找到一个顶点子集Y,使得X中每个顶点和Y中每个顶点之间都有边。

方法:二分图的最大团=补图的最大独立集。

补图的定义是:对于二分图中左边一点x和右边一点y,若x和y之间有边,那么在补图中没有,否则有。

这个方法很好理解,因为最大独立集是两两不相邻,所以最大独立集的补图两两相邻。

/*POJ 3692反过来建图,建立不认识的图,就变成求最大独立集了。*/#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>using namespace std;/* **************************************************************************//二分图匹配(匈牙利算法的DFS实现)//初始化:g[][]两边顶点的划分情况//建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配//g没有边相连则初始化为0//uN是匹配左边的顶点数,vN是匹配右边的顶点数//调用:res=hungary();输出最大匹配数//优点:适用于稠密图,DFS找增广路,实现简洁易于理解//时间复杂度:O(VE)//***************************************************************************///顶点编号从0开始的const int MAXN=510;int uN,vN;//u,v数目int g[MAXN][MAXN];int linker[MAXN];bool used[MAXN];bool dfs(int u)//从左边开始找增广路径{    int v;    for(v=0;v<vN;v++)//这个顶点编号从0开始,若要从1开始需要修改      if(g[u][v]&&!used[v])      {          used[v]=true;          if(linker[v]==-1||dfs(linker[v]))          {//找增广路,反向              linker[v]=u;              return true;          }      }    return false;//这个不要忘了,经常忘记这句}int hungary(){    int res=0;    int u;    memset(linker,-1,sizeof(linker));    for(u=0;u<uN;u++)    {        memset(used,0,sizeof(used));        if(dfs(u)) res++;    }    return res;}//******************************************************************************/int main(){     int m;     int u,v;     int iCase=0;     while(scanf("%d%d%d",&uN,&vN,&m)!=EOF)     {         iCase++;         if(uN==0&&vN==0&&m==0)break;         for(int i=0;i<uN;i++)           for(int j=0;j<vN;j++)              g[i][j]=1;         while(m--)         {             scanf("%d%d",&u,&v);             u--;             v--;             g[u][v]=0;         }         printf("Case %d: %d\n",iCase,uN+vN-hungary());     }     return 0;}


原创粉丝点击