• HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流


    二分+最大流:

      1 //题目大意:有编号为1~n的女生和1~n的男生配对
      2 //
      3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架
      4 //
      5 //然后输入f组,c,d表示编号为c的女生和编号为d的女生是朋友
      6 //
      7 //进行配对的要求满足其一即可。 
      8 //1.a女生没有和b男生吵过架 
      9 //2.a女生的朋友和b男生没有吵过架
     10 //
     11 //每进行一轮之后重新配对,配过得一对不可再配,问最多能进行几轮。
     12 //
     13 //题解:
     14 //这一道题要二分答案,然后用最大流来跑
     15 //可能很疑惑最大流怎么去跑这个题目,我们可以假设可以进行mid轮,然后我们从起点给女生连一条容量为mid的
     16 //边,然后终点也和男孩之间连一条容量为mid的边。之后如果男孩和女孩之间可以组成情侣那就连一条容量为1的
     17 //边。这样的话当mid==1的时候,你跑最大流相当于每一个女孩找到了一个互不相同的男孩(因为一个男孩和终点容
     18 //量为1,对吧!!),当mid>1的时候,这个时候对于一个男孩可以被选择mid次(保证这个mid是可行解),因为每一
     19 //个女生和一个男生的边容量只是1,所以一个女生不可能选择多次是同一个男生。那么对于所有男生都会有mid个
     20 //女生选择他们,那么这样的话就刚好可以凑成mid轮
     21 
     22 #include<stdio.h>
     23 #include<string.h>
     24 #include<iostream>
     25 #include<algorithm>
     26 #include<queue>
     27 using namespace std;
     28 const int maxn=1010;
     29 const int INF=0x3f3f3f3f;
     30 int head[maxn],cnt,st,en,dis[maxn],cur[maxn],w[105][105],q[105][105];
     31 struct edge
     32 {
     33     int v,next,c,flow;
     34 } e[100000];
     35 void add_edge(int x,int y,int z)
     36 {
     37     e[cnt].v=y;
     38     e[cnt].c=z;
     39     e[cnt].flow=0;
     40     e[cnt].next=head[x];
     41     head[x]=cnt++;
     42 
     43     e[cnt].v=x;
     44     e[cnt].c=0;
     45     e[cnt].flow=0;
     46     e[cnt].next=head[y];
     47     head[y]=cnt++;
     48 }
     49 bool bfs()
     50 {
     51     memset(dis,0,sizeof(dis));
     52     dis[st]=1;
     53     queue<int>r;
     54     r.push(st);
     55     while(!r.empty())
     56     {
     57         int x=r.front();
     58         r.pop();
     59         for(int i=head[x]; i!=-1; i=e[i].next)
     60         {
     61             int v=e[i].v;
     62             if(!dis[v] && e[i].c>e[i].flow)
     63             {
     64                 dis[v]=dis[x]+1;
     65                 r.push(v);
     66             }
     67         }
     68     }
     69     return dis[en];
     70 }
     71 int dinic(int s,int limit)
     72 {
     73     if(s==en || !limit) return limit;
     74     int ans=0;
     75     for(int &i=cur[s]; i!=-1; i=e[i].next)
     76     {
     77         int v=e[i].v,feed;
     78         if(dis[v]!=dis[s]+1) continue;
     79         feed=dinic(v,min(limit,e[i].c-e[i].flow));
     80         if(feed)
     81         {
     82             e[i].flow+=feed;
     83             e[i^1].flow-=feed;
     84             limit-=feed;
     85             ans+=feed;
     86             if(limit==0) break;
     87         }
     88     }
     89     if(!ans) dis[s]=-1;
     90     return ans;
     91 }
     92 int main()
     93 {
     94     int t;
     95     scanf("%d",&t);
     96     while(t--)
     97     {
     98         memset(w,0,sizeof(w));
     99         memset(q,0,sizeof(q));
    100         st=0;
    101         int n,m,f,x,y;
    102         scanf("%d%d%d",&n,&m,&f);
    103         en=2*n+1;
    104         for(int i=1; i<=m; ++i)
    105         {
    106             scanf("%d%d",&x,&y);
    107             q[x][y]=1;
    108         }
    109         for(int i=1; i<=f; ++i)
    110         {
    111             scanf("%d%d",&x,&y);
    112             w[x][y]=w[y][x]=1;
    113         }
    114 
    115         int l=0,r=n,mid,flag=0,sum;
    116         while(l<=r)
    117         {
    118             mid=(l+r)>>1;
    119             memset(head,-1,sizeof(head));
    120             cnt=0;
    121             for(int i=1; i<=n; ++i)
    122             {
    123                 add_edge(st,i,mid);
    124                 add_edge(i+n,en,mid);
    125             }
    126             for(int i=1; i<=n; ++i)
    127             {
    128                 for(int j=1; j<=n; ++j)
    129                 {
    130                     if(i==j) continue;
    131                     if(w[i][j])
    132                     {
    133                         for(int k=1; k<=n; ++k)
    134                         {
    135                             if(q[j][k])
    136                             {
    137                                 q[i][k]=1;
    138                             }
    139                         }
    140                     }
    141                 }
    142             }
    143             for(int i=1; i<=n; ++i)
    144             {
    145                 for(int j=1; j<=n; ++j)
    146                 {
    147                     if(q[i][j])
    148                         add_edge(i,j+n,1);
    149                 }
    150             }
    151             int ans=0;
    152             while(bfs())
    153             {
    154                 for(int i=0; i<=en; i++)
    155                     cur[i]=head[i];
    156                 ans+=dinic(st,INF); //这里原来是1我改成了INF,是这里的错.变成1的话最大流算法跑了好多次,就会TLE
    157             }
    158             if(ans>=n*mid)   
    159             {
    160                 sum=mid;
    161                 l=mid+1;
    162             }
    163             else r=mid-1;
    164         }
    165 
    166         printf("%d
    ",sum);
    167 
    168     }
    169     return 0;
    170 }

    二分匹配:

      1 //还可以用二分图匹配+并查集来写(我是用的最大流,以下代码转自:https://blog.csdn.net/loy_184548/article/details/51461601)
      2 //
      3 //题目大意:有编号为1~n的女生和1~n的男生配对
      4 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架
      5 //
      6 //然后输入f组,c,d表示编号为c的女生和编号为d的女生是朋友
      7 //
      8 //进行配对的要求满足其一即可。 
      9 //1.a女生没有和b男生吵过架 
     10 //2.a女生的朋友和b男生没有吵过架
     11 //
     12 //每进行一轮之后重新配对,配过得一对不可再配,问最多能进行几轮。
     13 //
     14 //题目思路:
     15 //第一步:要求2可以处理一下变成要求1.这里就需要用到并查集啦(刚开始用dfs处理,然而超内存了)
     16 //1.两个女生是朋友就用并查集合并 
     17 //2.遍历,如果两个女生a,b父节点一样,那么b所能配对的男生a也能配对
     18 
     19 //  链接:https://blog.csdn.net/loy_184548/article/details/51461601
     20 //  HDU-3081.cpp
     21 //  HDU
     22 //
     23 //  Created by pro on 16/5/20.
     24 //  Copyright (c) 2016年 loy. All rights reserved.
     25 //
     26 
     27 #include <iostream>
     28 #include <cstdio>
     29 #include <cmath>
     30 #include <vector>
     31 #include <cstring>
     32 #include <algorithm>
     33 #include <string>
     34 #include <set>
     35 #include <functional>
     36 #include <numeric>
     37 #include <sstream>
     38 #include <stack>
     39 #include <map>
     40 #include <queue>
     41 #include<iomanip>
     42 using namespace std;
     43 int g[105][105];
     44 #define MAXN 105
     45 int fa[MAXN] = {0};
     46 int vis[105];
     47 int link[105];  //编号为i的女生对应的男生编号
     48 int n,m,f,ans = 0;
     49 void initialise(int n)          //初始化
     50 {
     51     for (int i = 1; i <= n; i++)
     52         fa[i] = i;
     53 }
     54 int getfather(int v)            //父节点
     55 {
     56     return (fa[v] == v) ? v : fa[v] = getfather(fa[v]);
     57 }
     58 void merge(int x,int y)         //合并
     59 {
     60     x = getfather(x);
     61     y = getfather(y);
     62     if (x != y)
     63         fa[x] = y;
     64 }
     65 
     66 bool dfs(int u) {
     67     for (int v = 1; v <= n; v++) {
     68         if (!vis[v] && g[u][v]) {
     69             vis[v] = 1;
     70             if (!link[v] || dfs(link[v])) {
     71                 link[v] = u;
     72                 return true;
     73             }
     74         }
     75     }
     76     return false;
     77 }
     78 void solve()
     79 {
     80     while(1)
     81     {
     82        // cout << ans << endl;
     83         memset(link,0,sizeof(link));
     84         int cnt = 0;
     85         for (int i = 1; i <= n; i++)
     86         {
     87             memset(vis,0,sizeof(vis));
     88             if (dfs(i)) cnt++;  //如果找到了能配对的
     89         }
     90         if (cnt == n) //如果全部配对成功
     91         {
     92             ans++;
     93             for (int i = 1; i <= n; i++)
     94             {
     95                 g[link[i]][i] = 0;   //编号为i以及对应的女生不能再连
     96             }
     97         }
     98         else
     99         {
    100             break;
    101         }
    102     }
    103 }
    104 int main()
    105 {
    106     int t;
    107     scanf("%d",&t);
    108     while(t--)
    109     {
    110         int u,v;
    111         scanf("%d%d%d",&n,&m,&f);
    112         memset(g,0,sizeof(g));
    113         initialise(n);
    114         ans = 0;
    115         for (int i = 0; i < m; i++)
    116         {
    117             scanf("%d%d",&u,&v);
    118             g[u][v] = 1;
    119         }
    120         for (int i = 0; i < f; i++)
    121         {
    122             scanf("%d%d",&u,&v);
    123             merge(u,v);
    124         }
    125         for (int i = 1; i <= n; i++)
    126         {
    127             int t = getfather(i);//得到编号为i这个女生的父节点
    128 
    129             for (int j = 1; j <= n; j++)
    130             {
    131                 if (i != j && getfather(j) == t)  //如果两个女生是朋友
    132                 {
    133                     for (int k = 1; k <= n; k++)  //那么j的朋友k,也是i的朋友
    134                     {
    135                         if (g[j][k]) g[i][k] = 1;
    136                     }
    137                 }
    138             }
    139         }
    140         solve();
    141         printf("%d
    ",ans);
    142     }
    143     return 0;
    144 }
  • 相关阅读:
    redis应用场景之文章投票设计思路
    Redis存储的5种数据结构
    v+=e 不等价于 v=v+e
    WebMagic
    指针函数和函数指针的区别
    为什么说StringBuilder不安全?
    sql注入
    Autowired报错处理
    SpringBoot入门最简单的一个项目示例
    MVC中Cookie的用法(二)---CookieHelper
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/11806032.html
Copyright © 2020-2023  润新知