zoukankan      html  css  js  c++  java
  • HDU 3081 Marriage Match II 最大流OR二分匹配

     Marriage Match IIHDU - 3081

    题目大意:每个女孩子可以和没有与她或者是她的朋友有过争吵的男孩子交男朋友,现在玩一个游戏,每一轮每个女孩子都要交一个新的男朋友,问最多可以玩多少轮?

    首先要想知道每个女孩子能够和哪些男孩子交朋友,就得通过并查集来处理了,每个女孩子可以交朋友的男孩子,和她是朋友的女孩子同样可以交。

    然后就是怎么知道能玩几轮。有两个方法。第一个就是最大流。

    具体思路就是二分答案,每个女孩子都可以和能和他交朋友的男孩子建一条流量为1的边,就代表可以和他交一次朋友,然后源点与每个女孩子连一条流量为当前二分的这个答案的边,汇点也与每个男孩子连一条流量为当前二分的这个答案的流,这样的话能每个女孩子能够满流的话就是能够玩这么多轮,当前答案是符合的。

      1 #include<cstdio>
      2 #include<queue>
      3 #include<algorithm>
      4 using namespace std;
      5 const int N=218,M=52118,inf=1000000007;
      6 struct Side{
      7     int v,ne,w;
      8 }S[M];
      9 int n,sn,sb,se,head[N],dep[N],cur[N],fa[N],ok[N][N];
     10 void init()
     11 {
     12     sn=0;
     13     sb=0,se=2*n+1;
     14     for(int i=sb;i<=se;i++)
     15         head[i]=-1;
     16 }
     17 void add(int u,int v,int w)
     18 {
     19     S[sn].w=w;
     20     S[sn].v=v;
     21     S[sn].ne=head[u];
     22     head[u]=sn++;
     23 }
     24 void addE(int u,int v,int w)
     25 {
     26     add(u,v,w);
     27     add(v,u,0);
     28 }
     29 int gui(int x){
     30     return fa[x]==x ? x : fa[x]=gui(fa[x]);
     31 }
     32 void bing(int x,int y)
     33 {
     34     int gx=gui(x),gy=gui(y);
     35     if(gx!=gy)
     36         fa[gx]=gy;
     37 }
     38 void bulidE(int limit)
     39 {
     40     init();
     41     for(int i=1;i<=n;i++)
     42         addE(sb,i,limit);
     43     for(int i=1;i<=n;i++)
     44         addE(n+i,se,limit);
     45     for(int i=1;i<=n;i++)
     46         for(int j=1;j<=n;j++)
     47             if(ok[i][j])
     48                 addE(i,n+j,1);
     49 }
     50 bool bfs()
     51 {
     52     for(int i=sb;i<=se;i++)
     53         dep[i]=0;
     54     dep[sb]=1;
     55     queue<int> q;
     56     q.push(sb);
     57     int u,v;
     58     while(!q.empty()){
     59         u=q.front();
     60         q.pop();
     61         for(int i=head[u];~i;i=S[i].ne){
     62             v=S[i].v;
     63             if(S[i].w>0&&!dep[v]){
     64                 dep[v]=dep[u]+1;
     65                 if(v==se)
     66                     return true;
     67                 q.push(v);
     68             }
     69         }
     70     }
     71     return false;
     72 }
     73 int dfs(int u,int minf)
     74 {
     75     if(u==se||!minf)
     76         return minf;
     77     int v,flow;
     78     for(int &i=cur[u];~i;i=S[i].ne){
     79         v=S[i].v;
     80         if(S[i].w>0&&dep[v]==dep[u]+1){
     81             flow=dfs(v,min(minf,S[i].w));
     82             if(flow>0){
     83                 S[i].w-=flow;
     84                 S[i^1].w+=flow;
     85                 return flow;
     86             }
     87         }
     88     }
     89     return 0;
     90 }
     91 int dinic()
     92 {
     93     int maxf=0,flow;
     94     while(bfs()){
     95         for(int i=sb;i<=se;i++)
     96             cur[i]=head[i];
     97         while(flow=dfs(sb,inf))
     98             maxf+=flow;
     99     }
    100     return maxf;
    101 }
    102 int solve()
    103 {
    104     int l=0,r=n,mid,ans=0;
    105     while(l<=r){
    106         mid=(l+r)>>1;
    107         bulidE(mid);
    108         if(dinic()==n*mid)
    109             ans=mid,l=mid+1;
    110         else
    111             r=mid-1;
    112     }
    113     return ans;
    114 }
    115 int main()
    116 {
    117     int t,m,f,a,b;
    118     scanf("%d",&t);
    119     while(t--)
    120     {
    121         scanf("%d%d%d",&n,&m,&f);
    122         for(int i=1;i<=n;i++){
    123             fa[i]=i;
    124             for(int j=1;j<=n;j++)
    125                 ok[i][j]=0; 
    126         }
    127         while(m--){
    128             scanf("%d%d",&a,&b);
    129             ok[a][b]=1;
    130         }
    131         while(f--){
    132             scanf("%d%d",&a,&b);
    133             bing(a,b);
    134         }
    135         for(int i=1;i<=n;i++)
    136             for(int j=1;j<=n;j++)
    137                 for(int k=1;k<=n;k++)
    138                     if(gui(i)==gui(j)&&ok[i][k])
    139                         ok[j][k]=1;
    140         printf("%d
    ",solve());
    141     }
    142     return 0;
    143 }
    最大流

    第二种就是二分匹配。我们每次跑一遍匈牙利为每个女孩子匹配一个男孩子,然后再把他们的关系去掉继续匹配 ,最多能匹配多少轮,就是能玩多少轮。

     1 #include<cstdio>
     2 const int N=118;
     3 int n,fa[N],ok[N][N],vis[N],pp[N];
     4 int gui(int x){
     5     return fa[x]==x ? x : fa[x]=gui(fa[x]);
     6 }
     7 void bing(int x,int y)
     8 {
     9     int gx=gui(x),gy=gui(y);
    10     if(gx!=gy)
    11         fa[gx]=gy;
    12 }
    13 int match(int u)
    14 {
    15     for(int i=1;i<=n;i++){
    16         if(!vis[i]&&ok[u][i]){
    17             vis[i]=1;
    18             if(!pp[i]||match(pp[i])){
    19                 pp[i]=u;
    20                 return 1;
    21             }
    22         }
    23     }
    24     return 0;
    25 }
    26 int solve()
    27 {
    28     int ans=0,mm;
    29     while(1){
    30         mm=0;
    31         for(int i=1;i<=n;i++){
    32             for(int j=1;j<=n;j++)
    33                 vis[j]=0;
    34             mm+=match(i);
    35         }
    36         if(mm==n)
    37             ans++;
    38         else
    39             break;
    40         for(int i=1;i<=n;i++){
    41             ok[pp[i]][i]=0;
    42             pp[i]=0;
    43         }
    44     }
    45     return ans;
    46 }
    47 int main()
    48 {
    49     int t,m,f,a,b;
    50     scanf("%d",&t);
    51     while(t--)
    52     {
    53         scanf("%d%d%d",&n,&m,&f);
    54         for(int i=1;i<=n;i++){
    55             fa[i]=i;
    56             pp[i]=0;
    57             for(int j=1;j<=n;j++)
    58                 ok[i][j]=0; 
    59         }
    60         while(m--){
    61             scanf("%d%d",&a,&b);
    62             ok[a][b]=1;
    63         }
    64         while(f--){
    65             scanf("%d%d",&a,&b);
    66             bing(a,b);
    67         }
    68         for(int i=1;i<=n;i++)
    69             for(int j=1;j<=n;j++)
    70                 for(int k=1;k<=n;k++)
    71                     if(gui(i)==gui(j)&&ok[i][k])
    72                         ok[j][k]=1;
    73         printf("%d
    ",solve());
    74     }
    75     return 0;
    76 }
    二分匹配
  • 相关阅读:
    kmp 算法
    jdk 和 cglib 的动态代理
    RestTemplate工具类
    bat脚本切换多个工程的分支
    字符串的左旋转
    输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。
    枚举类型在JPA中的使用
    拾遗
    YAML DEMO
    kiali 1.26 anonymous策略修改为token
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/11212960.html
Copyright © 2011-2022 走看看