【二分图匹配+并查集+删边||二分答案+网络流+并查集】HDU - 3081 - Marriage Match II

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/81674507

题目链接<http://acm.hdu.edu.cn/showproblem.php?pid=3081>


题意:

n个女孩和n个男孩要一对一匹配。每个女孩可以选择自己喜欢的,也可以选择自己朋友喜欢的。朋友的关系是可以传递的。每一轮匹配,女孩匹配的男孩要不同,问最多能进行几轮的匹配。


题解一:

二分图匹配+删边+并查集。

每个女孩连接所有自己喜欢的和朋友喜欢的男孩。

每次进行一次二分图匹配,如果每个人都能被匹配就删去匹配的边。如果不能就输出答案。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#include<string.h>
int match[1005],vis[1005];
int n,m;
int mp[1005][1005];
bool dfs(int u){
    for(int v=1;v<=n;v++){
        if(mp[u][v]&&!vis[v]){
            vis[v]=true;
            if(match[v]==-1||dfs(match[v])){
                match[v]=u;
                return true;
            }
        }
    }
    return false;
}
int cal(){
    memset(match,-1,sizeof(match));
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(!dfs(i)) return i-1;
    }
    return n;
}
int t,f;
int fa[105];
int fd(int x){return x==fa[x]?x:fa[x]=fd(fa[x]);}
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&f);
        memset(mp,0,sizeof(mp));
        int u,v;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            mp[u][v]=1;
        }
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=f;i++){
            scanf("%d%d",&u,&v);
            int fu=fd(u),fv=fd(v);
            fa[fu]=fv;
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                int fi=fd(i),fj=fd(j);
                if(fi!=fj) continue;
                for(int k=1;k<=n;k++)
                    mp[i][k]=mp[j][k]=(mp[i][k]||mp[j][k]);
            }
        }
        int ans=0;
        while(1){
            if(cal()<n) break;
            ans++;
            for(int i=1;i<=n;i++)
                mp[match[i]][i]=0;
        }
        printf("%d\n",ans);
    }
    return 0;
}

题解二

二分答案+最大流+并查集。

每个女孩连接所有自己喜欢的和朋友喜欢的男孩。

二分一个答案,如果最大流的流量是n*mid,那就满足。

这就跟这题很像了:https://blog.csdn.net/monochrome00/article/details/81459335

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
const int N=10007;
const int inf=1<<26;
struct Edge{
    int u,v,w,nxt;
    Edge(int u=0,int v=0,int w=0,int nxt=0):u(u),v(v),w(w),nxt(nxt){}
}edge[30*N];
int n,m,edn,sp,tp;
int p[N],d[N],c[N];
void add(int u,int v,int w){
    edge[edn]=Edge(u,v,w,p[u]);p[u]=edn++;
    edge[edn]=Edge(v,u,0,p[v]);p[v]=edn++;
}
bool bfs(){
    memset(d,-1,sizeof(d));d[sp]=0;
    queue<int>q;q.push(sp);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=p[u];~i;i=edge[i].nxt){
            int v=edge[i].v;
            if(d[v]==-1&&edge[i].w){
                d[v]=d[u]+1;
                q.push(v);
                if(v==tp) return true;
            }
        }
    }
    return ~d[tp];
}
int dfs(int u,int b){
    if(u==tp) return b;
    int r=0;
    for(int i=c[u];~i;i=edge[i].nxt){
        int v=edge[i].v;
        if(edge[i].w&&d[v]==d[u]+1){
            int x=min(edge[i].w,b-r);
            c[u]=i;
            x=dfs(v,x);
            r+=x;
            edge[i].w-=x;
            edge[i^1].w+=x;
            if(r==b) break;
        }
    }
    if(!r)d[u]=-2;
    return r;
}
int dinic(){
    int total=0,t;
    while(bfs()){
        memcpy(c,p,sizeof(p));
        while(t=dfs(sp,inf))
        total+=t;
    }
    return total;
}
int t,f;
int mp[105][105],fa[105];
int fd(int x){return x==fa[x]?x:fa[x]=fd(fa[x]);}
void build(int k){
    memset(p,-1,sizeof(p));edn=0;
    for(int i=1;i<=n;i++){
        add(i+n,tp,k);
        add(sp,i,k);
        for(int j=1;j<=n;j++){
            if(mp[i][j])
                add(i,j+n,1);
        }
    }
}
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&f);
        memset(mp,0,sizeof(mp));
        sp=0,tp=2*n+1;
        int u,v;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            mp[u][v]=1;
        }
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=f;i++){
            scanf("%d%d",&u,&v);
            int fu=fd(u),fv=fd(v);
            fa[fu]=fv;
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                int fi=fd(i),fj=fd(j);
                if(fi!=fj) continue;
                for(int k=1;k<=n;k++)
                    mp[i][k]=mp[j][k]=(mp[i][k]||mp[j][k]);
            }
        }
        int lo=0,hi=100;
        while(lo<=hi){
            int mid=lo+hi>>1;
            build(mid);
            if(dinic()>=mid*n) lo=mid+1;
            else hi=mid-1;
        }
        printf("%d\n",hi);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/81674507
今日推荐