zoukankan      html  css  js  c++  java
  • HDU 3081 Marriage Match II (二分+网络流+并查集)

    注意

    这题需要注意的有几点。

    • 首先板子要快,尽量使用带当前弧优化的dinic,这样跑起来不会超时。
    • 使用弧优化的时候,如果源点设置成0,记得将cur数组从0开始更新,因为有的板子并不是。
    • 其次这题是多组样例输入,所以每次需要清空head数组,pre数组,deep数组,vis数组等等,以及建图之前将cnt设置为0。

    题意

    有n个女孩和n个男孩,给出哪些女孩和哪些男孩从未发生冲突,以及女孩之间的朋友关系,朋友关系是传递的。
    每次所有女孩都选择不同一个男孩作为自己的伴侣,问能选择几轮?
    女孩选择男孩的条件是,女孩从未和该男孩发生冲突,或者她的朋友从未和该男孩发生冲突。

    思路

    1. 用并查集将女孩分组,同一个组内的女孩,共享他们喜欢的男孩。
    2. 然后就是二分图匹配,建立源点和汇点,源点连接女孩,汇点连接男孩(以下简称源点汇点路径),女孩喜欢男孩,就建一条边。
      如果源点汇点路径权值为1,那么这个最大流跑出来就是女孩和男孩的最大匹配方案数。
    3. 这题问的是每次每位女孩都选择不同的男孩,并且每位女孩都要有人能匹配,所以,我们二分源点汇点路径的权值大小。
      易知,如果源点汇点路径权值 k <= ans ,那么最大流 maxflow==n*k 。
      因为每个人跑都是满流,所以此时可以尝试将k增加,如果不等于,说明k值过大,应将k值减小。
      AC 31ms
    #include <iostream>
    #include <stdio.h>
    #include <queue>
    #include <string.h>
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int maxn=210;
    const int maxm=21000;
    bool bridge[maxn][maxn];
    int pre[maxn];
    
    struct Edge {
        int from,to,cap,flow;
    };
    
    struct Dinic {
        Edge edge[maxm];
        int next[maxm];
        int head[maxn];
        int deep[maxn];
        int cur[maxn];
        int vis[maxn];
        int n,m,s,t,cnt=0;
    
        void init_point(int nn,int mm ,int ss,int tt) {
            n=nn;
            m=mm;
            s=ss;
            t=tt;
        }
    
        void init() {
            memset(head,-1,sizeof(head));
            cnt=0;
        }
    
        void addEdge(int u,int v,int w) {
            edge[cnt].cap=w;
            edge[cnt].flow=0;
            edge[cnt].from=u;
            edge[cnt].to=v;
            next[cnt]=head[u];
            head[u]=cnt++;
    
            edge[cnt].cap=0;
            edge[cnt].flow=0;
            edge[cnt].from=v;
            edge[cnt].to=u;
            next[cnt]=head[v];
            head[v]=cnt++;
        }
    
        void build(int value) {
            init();
            for (int i=1;i<=n;i++) {
                addEdge(s,i,value);
            }
            for (int i=n+1;i<=2*n;i++) {
                addEdge(i,t,value);
            }
            for (int i=1;i<=n;i++) {
                for (int j=n+1;j<=2*n;j++) {
                    if (bridge[i][j]) {
                        addEdge(i,j,1);
                    }
                }
            }
    //        for (int i=0;i<=n;i++) {
    //            printf("%d:",i);
    //            for (int j=head[i];j!=-1;j=next[j]) {
    //                printf("%d %d %d   ",edge[j].to,edge[j].cap,edge[j].flow);
    //            }
    //            printf("
    ");
    //        }
        }
    
        bool bfs() {
            memset(vis,0,sizeof(vis));
            memset(deep,0,sizeof(deep));
            queue<int> q;
            deep[s]=0;
            vis[s]=true;
            q.push(s);
            while (!q.empty()) {
                int u=q.front();
                q.pop();
                for (int i=head[u];i!=-1;i=next[i]) {
                    Edge &e=edge[i];
                    if (!vis[e.to]&&e.cap>e.flow) {
                        deep[e.to]=deep[u]+1;
                        vis[e.to]=true;
                        q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int dfs(int u,int in) {
            if (u==t||in==0) {
                return in;
            }
            int out=0,f;
            for (int& i=cur[u];i!=-1;i=next[i]) {
                int v=edge[i].to;
                if (deep[v]==deep[u]+1&&(f=dfs(v,min(in,edge[i].cap-edge[i].flow)))>0) {
                    edge[i].flow+=f;
                    edge[i^1].flow-=f;
                    out+=f;
                    in-=f;
                    if (in==0) {
                        break;
                    }
                }
            }
            return out;
        }
    
        int maxflow() {
            int ans=0;
            while (bfs()) {
                for (int i=0;i<=2*n+1;i++) {
                    cur[i]=head[i];
                }
                ans+=dfs(s,INF);
            }
            return ans;
        }
    
    }DC;
    
    int findset(int x)
    {
        if (x==pre[x]) {
            return x;
        }
        return pre[x]=findset(pre[x]);
    }
    
    void unions(int a,int b)
    {
        int x=findset(a);
        int y=findset(b);
        if (x!=y) {
            pre[x]=y;
        }
    }
    
    int main()
    {
        int T,f,n,m,x,y;
        scanf("%d",&T);
        while (T--) {
            scanf("%d%d%d",&n,&m,&f);
            DC.init_point(n,m,0,2*n+1);
            memset(bridge,0,sizeof(bridge));
            for (int i=0;i<maxn;i++) {
                pre[i]=i;
            }
            for (int i=0;i<m;i++) {
                scanf("%d%d",&x,&y);
                bridge[x][y+n]=true;
            }
            for (int i=0;i<f;i++) {
                scanf("%d%d",&x,&y);
                unions(x,y);
            }
            for (int i=1;i<=n;i++) {
                for (int j=i+1;j<=n;j++) {
                    if (findset(i)==findset(j)) {
                        for (int k=n+1;k<=2*n;k++) {
                            if (bridge[i][k]||bridge[j][k]) {
                                bridge[i][k]=bridge[j][k]=true;
                            }
                        }
                    }
                }
            }
            int l=0,r=100,ans,mid;
            while (l<=r) {
                mid=(l+r)>>1;
                DC.build(mid);
                if (DC.maxflow()==n*mid) {
                    ans=mid;
                    l=mid+1;
                }
                else {
                    r=mid-1;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    Provisioning profile 浅析
    Swift --> Map & FlatMap
    Swift 学习笔记(五)
    Swift 学习笔记(四)
    Swift 学习笔记 (三) 之循环引用浅析
    Swift 学习笔记 (二)
    HomeBrew
    UIGestureRecognizer 手势浅析
    frame、bounds表示大小和位置的属性以及center、position、anchorPosition
    UIViewContentMode 图文解说
  • 原文地址:https://www.cnblogs.com/xyqxyq/p/12328891.html
Copyright © 2011-2022 走看看