• 网络流24题-飞行员配对方案问题


    题目链接:https://www.luogu.org/problemnew/show/P2756

    经典的二分图最大匹配问题。

    我们用最大流来做

    首先从源点向外籍飞行员编号连容量为1的边,每个英国飞行员编号向汇点连容量为1的边,二分图内的边连容量为inf的边

    跑一遍最大流,判断边是否有流量,即反向弧不为零的边

    dinic算法

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 const int inf=0x3f3f3f3f; //int的最大值
      5 const int MAXN=1000,MAXM=100000; //N为点数,M为边数
      6 struct node
      7 {
      8     int v,nxt,f;
      9 }edge[MAXM*2+10];
     10 int S,T,tot,head[MAXN+10]; //S为源点,T为汇点
     11 void add(int u,int v,int c) //添加正向边和反向边
     12 {
     13     edge[++tot].v=v;    edge[tot].f=c;  edge[tot].nxt=head[u];  head[u]=tot;
     14     edge[++tot].v=u;    edge[tot].f=0;  edge[tot].nxt=head[v];  head[v]=tot;
     15 }
     16 void init()//初始化
     17 {
     18     memset(head,0,sizeof(head));
     19     tot=1;
     20 }
     21 queue<int>q;
     22 int depth[MAXN+10];
     23 bool bfs()
     24 {
     25     memset(depth,0,sizeof(depth));
     26     while(!q.empty()) q.pop();
     27     q.push(S);
     28     depth[S]=1;
     29     while(!q.empty())
     30     {
     31         int x=q.front();q.pop();
     32         for(int i=head[x];i;i=edge[i].nxt)
     33         {
     34             int v=edge[i].v;
     35             if(edge[i].f&&!depth[v])
     36             {
     37                 q.push(v);
     38                 depth[v]=depth[x]+1;
     39                 if(v==T)    return 1;
     40 
     41             }
     42         }
     43     }
     44     return 0;
     45 }
     46 int dfs(int x,int flow)
     47 {
     48     if(x==T)    return flow;
     49     int rest=flow,w;
     50     for(int i=head[x];i&&rest;i=edge[i].nxt)
     51     {
     52         int v=edge[i].v;
     53         if(edge[i].f&&depth[v]==depth[x]+1)
     54         {
     55             w=dfs(v,min(rest,edge[i].f));
     56             if(!w)  depth[v]=0;
     57             edge[i].f-=w;
     58             edge[i^1].f+=w;
     59             rest-=w;
     60         }
     61     }
     62     return flow-rest;
     63 }
     64 int dinic()
     65 {
     66     int flow,maxflow=0;
     67     while(bfs())
     68     {
     69         while(flow=dfs(S,inf))    maxflow+=flow;
     70     }
     71     return maxflow;
     72 }
     73 int main()
     74 {
     75     int n,m,x,y;
     76     init();
     77     scanf("%d%d",&m,&n);
     78     S=0;T=n+1;
     79     while(1)
     80     {
     81         scanf("%d%d",&x,&y);
     82         if(x==-1&&y==-1)    break;
     83         add(x,y,inf);
     84     }
     85     for(int i=1;i<=m;i++)   add(S,i,1);
     86     for(int i=m+1;i<=n;i++) add(i,T,1);
     87     int maxflow=dinic();
     88     if(maxflow==0)
     89     {
     90         printf("No Solution!
    ");
     91         return 0;
     92     }
     93     printf("%d
    ",maxflow);
     94     for(int i=2;i<=tot;i+=2)
     95     {
     96         if(edge[i].v!=S&&edge[i^1].v!=S&&edge[i].v!=T&&edge[i^1].v!=T&&edge[i^1].f!=0)
     97             printf("%d %d
    ",edge[i^1].v,edge[i].v);
     98     }
     99     return 0;
    100 }
    View Code

     匈牙利算法

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 const int inf=0x3f3f3f3f;
     5 const int MAXN=10000;
     6 const int MAXM=100000;
     7 struct Edge
     8 {
     9     int to,nxt;
    10 }edge[MAXM];
    11 int head[MAXN],tot,match[MAXN];
    12 bool vis[MAXN];
    13 void init()
    14 {
    15     tot=0;
    16     memset(head,-1,sizeof(head));
    17 }
    18 void addedge(int u,int v)
    19 {
    20     edge[tot].to=v; edge[tot].nxt=head[u];  head[u]=tot++;
    21 }
    22 bool dfs(int x)
    23 {
    24     for(int i=head[x];i!=-1;i=edge[i].nxt)
    25     {
    26         int y=edge[i].to;
    27         if(!vis[y])
    28         {
    29             vis[y]=1;
    30             if(!match[y]||dfs(match[y]))
    31             {
    32                 match[y]=x;
    33                 return true;
    34             }
    35 
    36         }
    37     }
    38     return false;
    39 }
    40 int solve(int N)
    41 {
    42     int ans=0;
    43     memset(match,0,sizeof(match));
    44     for(int i=0;i<N;i++)//点的编号为0~N-1
    45     {
    46         memset(vis,0,sizeof(vis));
    47         if(dfs(i))  ans++;
    48     }
    49     return ans;
    50 }
    51 int n,m;
    52 int main()
    53 {
    54     ios::sync_with_stdio(false);
    55     cin.tie(0);cout.tie(0);
    56     cin>>m>>n;
    57     int x,y;
    58     init();
    59     while(1)
    60     {
    61         cin>>x>>y;
    62         if(x==-1&&y==-1)    break;
    63         addedge(x,y);
    64     }
    65     cout<<solve(n)<<endl;
    66     for(int i=1;i<=n;i++)
    67     {
    68         if(match[i])
    69             cout<<match[i]<<" "<<i<<endl;//注意方向
    70     }
    71     return 0;
    72 }
    View Code
    如有错误,请指正,感谢!
  • 相关阅读:
    JavaScript作用域闭包(你不知道的JavaScript)
    Python笔记---错误笔记
    Go语言核心之美 1.5-作用域
    Android经常使用自己定义控件(二)
    Java开发者最经常使用19个Linux命令
    Python: scikit-image binary descriptor
    android 自己定义状态栏和导航栏分析与实现
    程序猿增加新团队的那些坑
    LeetCode 06 ZigZag Conversion
    【UWP通用应用开发】控件、应用栏
  • 原文地址:https://www.cnblogs.com/scott527407973/p/9736590.html
Copyright © 2020-2023  润新知