HDU 3081 Marriage Match Il【并查集 + 二分匹配】

题意: 有 2*n个同学,n男n女,知道了 有 m 对 男女之间木有吵过架,现在这 n 个女生要找对象,要求没有和她吵过架或者没有和她的一个朋友吵过架,

         当 n 个女生都找到对象的时候算作一轮,然后重新找,满足每个女生都不能找和上次一样的对象,问最多能进行多少轮。

分析: 将是朋友关系的女生放到一个集合,用来降低建图的时间复杂度。

#include <stdio.h>
#include <string.h>
#define maxn 102
#define clr(x)memset(x,0,sizeof(x))
int f[maxn];
int search(int x)
{
    return f[x] == x?x:(f[x] = search(f[x]));
}
void join(int x,int y)
{
    int fx = search(x);
    int fy = search(y);
    if(fx != fy){
        if(fx < fy)
            f[fy] = fx;
        else f[fx] = fy;
    }
}
int link[maxn];
int v[maxn];
int g[maxn][maxn];
int tt[maxn][maxn];
int n;
int find(int x)
{
    int i;
    for(i = 1; i <= n; i++){
        if(g[x][i]&&!v[i]){
            v[i] = 1;
            if(link[i] == 0||find(link[i])){
                link[i] = x;
                return 1;
            }
        }
    }
    return 0;
}
struct noql
{
    int girl,boy;
}r[maxn*maxn];
int main()
{
    int t;
    int m, F;
    int i, j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n, &m, &F);
        for(i = 1; i <= n; i++)
            f[i] = i;
        clr(g);
        int a,b;
        for(i = 1; i <= m; i++)
            scanf("%d %d",&r[i].girl, &r[i].boy);
        while(F--){
            scanf("%d %d",&a, &b);
            join(a,b);
        }
        for(i = 1; i <= m; i++)
            g[search(r[i].girl)][r[i].boy] =  1;
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
                if(g[search(i)][j] == 1)
                    g[i][j] = 1;
        int res = 0;
        while(1){
            clr(link);
            for(i = 1; i <= n; i++){
                clr(v);
                if(!find(i))
                    break;
            }
            if(i != n+1)
                break;
            res++;
            for(i = 1; i <= n; i++)
                g[link[i]][i] = 0;
        }
        printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-10-11 20:37  'wind  阅读(331)  评论(1编辑  收藏  举报