• hdu3081 Marriage Match II(二分+并查集+最大流)


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

    题意:

    n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她朋友能配对的男生配对。

    每次配对,每个女生都要跟不同的男生配对且每个女生都能配到对。问最多能配对几轮。

    思路:

    这道题乍看之下好像是二分匹配,但仔细一想是不太一样的。考虑用网络流做,首先女生可以与她朋友能配对的男生配对,这样需要用并查集保存他们可以配对的关系,这一点应该不难想到。接下来就是建图了,每个女生与可以配对的男生(包括朋友的可配对的男生)之间建边,容量为 1。 这样需要考虑的就是源点和女生、男生和汇点之间该如何建边了。

    本来考虑到n个女生和n个男生不重复完全配对最多只能进行n轮,想到可以将源点和女生、男生和汇点之间的容量赋为n,求出最大流。但是发现这样是不行的,如果有女生或者男生无法配对到,即一轮都无法进行,这样得到的答案就不对了。为了保证每一轮所有女生和男生都能匹配到,我们需要二分源点和女生、男生和汇点之间的容量k,并且需要保证满流。找到最大的满足条件的k就是答案。

    解法的正确性可以用数学归纳法证明,简单来说,当k=1时,转化为一个二分匹配,如果满流,就说明可以进行一轮。当k-1轮可以实现时(k-1满流),如果容量为k时满流,说明也可以实现k轮。这样就证明了正确性。

    由这个解法我们也可以想到用二分匹配的方法来解决:进行二分图的最大匹配,在匹配完成后判断匹配数是否等于n,不是的话说明GAME OVER 求得答案,是的话说明游戏能完成,然后进行删边操作,再继续匹配,直到匹配数<n为止。

    下面给出二分最大流的代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cmath>
      4 #include<cstring>
      5 
      6 using namespace std;
      7 const int MAXN = 2010;
      8 const int MAXM = 1200012;
      9 const int INF = 0x3f3f3f3f;
     10 struct Edge 
     11 {
     12     int to, next, cap, flow;
     13 }edge[MAXM];
     14 int tol;
     15 int head[MAXN];
     16 void init() 
     17 {
     18     tol = 2;
     19     memset(head, -1, sizeof(head));
     20 }
     21 void addedge(int u, int v, int w, int rw=0) 
     22 {
     23     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
     24     edge[tol].next = head[u]; head[u] = tol++;
     25     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
     26     edge[tol].next = head[v]; head[v] = tol++;
     27 }
     28 int Q[MAXN];
     29 int dep[MAXN], cur[MAXN], sta[MAXN];
     30 bool bfs(int s, int t, int n) 
     31 {
     32     int front = 0, tail = 0;
     33     memset(dep, -1, sizeof(dep[0])*(n+1));
     34     dep[s] = 0;
     35     Q[tail++] = s;
     36     while(front < tail)
     37     {
     38         int u = Q[front++];
     39         for(int i = head[u]; i != -1; i = edge[i].next) 
     40         {
     41             int v = edge[i].to;
     42             if(edge[i].cap > edge[i].flow && dep[v] == -1)                         {
     43                 dep[v] = dep[u] + 1;
     44                 if(v == t) return true;
     45                 Q[tail++] = v;
     46             }
     47         }
     48     }
     49     return false;
     50 }
     51 int dinic(int s, int t, int n) {
     52     int maxflow = 0;
     53     while(bfs(s, t, n)) {
     54         for(int i = 0; i < n; i++) cur[i] = head[i];
     55         int u = s, tail = 0;
     56         while(cur[s] != -1)
     57         {
     58             if(u == t) 
     59             {
     60                 int tp = INF;
     61                 for(int i = tail-1; i >= 0; i--)
     62                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
     63                 maxflow+=tp;
     64                 for(int i = tail-1; i >= 0; i--) {
     65                     edge[sta[i]].flow+=tp;
     66                     edge[sta[i]^1].flow-=tp;
     67                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
     68                         tail = i;
     69                 }
     70                 u = edge[sta[tail]^1].to;
     71             }
     72             else 
     73                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
     74                 {
     75                     sta[tail++] = cur[u];
     76                     u = edge[cur[u]].to;
     77                 }
     78                 else 
     79                 {
     80                     while(u != s && cur[u] == -1)
     81                         u = edge[sta[--tail]^1].to;
     82                     cur[u] = edge[cur[u]].next;
     83                 }
     84         }
     85     }
     86     return maxflow;
     87 }
     88 int n,m,f;
     89 int fa[MAXN];
     90 int map[120][120];
     91 
     92 int find(int x)
     93 {
     94     return fa[x]==x?x:fa[x]=find(fa[x]);
     95 }
     96 
     97 void unio(int x,int y)
     98 {
     99     int a=find(x),b=find(y);
    100     if(a!=b)
    101         fa[a]=b;
    102 }
    103 
    104 void build(int k)
    105 {
    106     init();
    107     for(int i=1;i<=n;++i)
    108     {
    109         addedge(0,i,k);
    110         addedge(i+n,2*n+1,k);
    111     }
    112     for(int i=1;i<=n;++i)
    113         for(int j=1;j<=n;++j)
    114             if(map[i][j])
    115                 addedge(i,n+j,1);
    116 }
    117 int main()
    118 {
    119     int t;
    120     scanf("%d",&t);
    121     while(t--)
    122     {
    123         scanf("%d%d%d",&n,&m,&f);
    124         for(int i=1;i<=n;++i)
    125             fa[i]=i;
    126         memset(map,0,sizeof(map));
    127         int a,b;
    128         for(int i=1;i<=m;++i)
    129         {
    130             scanf("%d%d",&a,&b);
    131             map[a][b]=1;
    132         }
    133         for(int i=1;i<=f;++i)
    134         {
    135             scanf("%d%d",&a,&b);
    136             unio(a,b);
    137         }
    138         for(int i=1;i<=n;++i)
    139             for(int j=1;j<=n;++j)
    140                 if(find(i)==find(j))
    141                     for(int k=1;k<=n;++k)
    142                         if(map[i][k])
    143                             map[j][k]=1;
    144         int s=0,t=n,ans;
    145         while(s<=t)
    146         {
    147             int mid=(s+t)/2;
    148             build(mid);
    149             if(mid*n==dinic(0,2*n+1,2*n+2))
    150             {
    151                 ans=mid;
    152                 s=mid+1;
    153             }
    154             else
    155                 t=mid-1;
    156         }
    157         cout<<ans<<endl;
    158     }
    159     return 0;
    160 }
  • 相关阅读:
    IP路由选择过程
    Netstat命令详解
    路由器的硬件结构
    路由器发展编年史 完结篇
    制作自己博客园文章签名
    路由器发展编年史 发展篇
    距离矢量路由协议_(4)
    路由器的基本功能
    分组交换、报文交换、电路交换
    动态路由中的几种常见metric
  • 原文地址:https://www.cnblogs.com/yaoyueduzhen/p/5087404.html
Copyright © 2020-2023  润新知