HDU 3277 Marriage Match III【并查集+二分+最大流】

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

          当 n 个女生都找到对象的时候算作一轮,然后重新找,满足每个女生都不能找和上次一样的对象,而且每个女生除了自己没有吵过架的人外,最多

          可一和 k 个男生成为朋友,问最多能进行多少轮。

分析: 建图:

          将每个女生 i  拆成两个点 i 和 i+n

          如果女生 i 可以和 男生 j 没吵过架,就在 i 和 j 之间连一条容量为 1 的边

          否则在 i+n 和 j 之间连一条容量为 1 的边

          在 i 和 i+n之间连一条容量为 k的边,

          在 s 和 1..n之间连边,容量为每个女生可以匹配的最大人数

          在 n*2+1..n*2+n 和 t 之间连边,容量为每个男生可以匹配的最大人数

          二分最大匹配人数,找到答案。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<climits>
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
const int INF=INT_MAX;
const int maxn=800;
const int maxm=1000000;
struct node
{
    int from,to,next,c;
}e[maxm];
int tot;
int head[maxn];
void add(int s,int u,int f1,int f2)
{
    e[tot].from=s;
    e[tot].to=u;
    e[tot].c=f1;
    e[tot].next=head[s];
    head[s]=tot++;
    e[tot].from=u;
    e[tot].to=s;
    e[tot].c=f2;
    e[tot].next=head[u];
    head[u]=tot++;
}
int q[maxn];
int cnt[maxn];
int d[maxn];
int low[maxn];
int cur[maxn];
int maxflow(int s,int t,int n)
{
    int *front=q,*rear=q;
    for(int i=0;i<n;i++)
    {
        d[i]=n;
        cnt[i]=0;
    }
    cnt[n]=n-1;
    cnt[0]++;
    d[t]=0;
    *rear++=t;
    while(front<rear)
    {
        int v=*front++;
        for(int i=head[v];i!=-1;i=e[i].next)
        {
            if(d[e[i].to]==n&&e[i^1].c>0)
            {
                d[e[i].to]=d[v]+1;
                cnt[n]--;
                cnt[d[e[i].to]]++;
                *rear++=e[i].to;
            }
        }
    }
    int flow=0, u=s, top=0;
    low[0]=INF;
    for(int i=0;i<n;i++)
        cur[i]=head[i];
    while(d[s]<n)
    {
        int &i=cur[u];
        for(;i!=-1;i=e[i].next)
        {
            if(e[i].c>0&&d[u]==d[e[i].to]+1)
            {
                low[top+1]=min(low[top],e[i].c);
                q[++top]=i;
                u=e[i].to;
                break;
            }
        }
        if(i!=-1)
        {
            if(u==t)
            {
                int minf=low[top];
                for(int p=1,i;p<=top;++p)
                {
                    i=q[p];
                    e[i].c-=minf;
                    e[i^1].c+=minf;
                }
                flow+=minf;
                u=s;
                low[0]=INF;
                top=0;
            }
        }
        else
        {
            int old_du=d[u];
            cnt[old_du]--;
            d[u]=n-1;
            for(int i=head[u];i!=-1;i=e[i].next)
                if(e[i].c>0&&d[u]>d[e[i].to])
                    d[u]=d[e[i].to];
            cnt[++d[u]]++;
            if(d[u]<n)
                cur[u]=head[u];
            if(u!=s)
            {
                u=e[q[top]].from;
                --top;
            }
            if(cnt[old_du]==0)
                break;
        }
    }
    return flow;
}
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;
    }
}
struct noq
{
    int girl,boy;
}re[maxn*maxn];
int g[maxn][maxn];
int K;
struct Edge
{
    int xu,flow;
}edge[1000000];
int top;
int ok(int ti,int s,int t,int n)
{
    int i, j, k;
    for(i = 0; i < 2*n; i++)
    {
        e[edge[i].xu].c = ti;
        e[edge[i].xu^1].c = 0;
    }
    for(i = 2*n; i < top; i++)
    {
        e[edge[i].xu].c = edge[i].flow;
        e[edge[i].xu^1].c = 0;
    }
    int res = maxflow(s,t,t+1);
    if(res == n*ti)
        return 1;
    return 0;
}
int main()
{
    int T, n, m;
    int i, j, k, F;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d %d",&n, &m, &K, &F);
        for(i = 1; i <= n; i++)
            f[i] = i;
        for(i =  1; i <= m; i++)
            scanf("%d %d",&re[i].girl,&re[i].boy);
        int a, b;
        while(F--){
            scanf("%d %d",&a, &b);
            join(a,b);
        }
        clr(g);
        for(i = 1; i <= m; i++)
            g[search(re[i].girl)][re[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 s = 0;
        int t = n*3+1;
        tot = 0;
        memset(head,-1,sizeof(head));
        top = 0;
        for(i = 1; i <= n; i++){
            edge[top++].xu = tot;
            add(s,i,1,0);
        }
        for(i = n*2+1; i <= n*3; i++)
        {
            edge[top++].xu = tot;
            add(i,t,1,0);
        }
         for(i = 1; i <= n; i++){
            edge[top].xu = tot;
            edge[top++].flow = K;
            add(i,i+n,K,0);
        }
        for(i = 1; i <= n; i++)
            for(j = 1; j <= n; j++)
            {
                if(g[i][j]){
                    edge[top].xu = tot;
                    edge[top++].flow = 1;
                    add(i,j+2*n,1,0);
                }
                else{
                    edge[top].xu = tot;
                    edge[top++].flow = 1;
                    add(i+n,j+2*n,1,0);
                }
            }
        int l = 0, r = n, mid;
        int res=0;
        while(l <= r){
            mid = (l+r)>>1;
            if(ok(mid,s,t,n)){
                res = mid;
                l = mid+1;
            }
            else r = mid-1;
        }
        printf("%d\n",res);
    }
    return 0;
}

 

posted @ 2012-10-11 23:34  'wind  阅读(431)  评论(0编辑  收藏  举报