• 最大流解二分图最大匹配问题


    从Byvoid大神博客那里拿到的好题和数据~在此鸣谢。

    问题描述:

    第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出
    的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞
    行员,另1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英
    国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的
    外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空
    军一次能派出最多的飞机。
    «编程任务:
    对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,
    使皇家空军一次能派出最多的飞机。
    «数据输入:
    由文件input.txt提供输入数据。文件第1 行有2个正整数m和n。n是皇家空军的飞行
    员总数(n<100);m是外籍飞行员数。外籍飞行员编号为1~m;英国飞行员编号为m+1~n。
    接下来每行有2 个正整数i和j,表示外籍飞行员i可以和英国飞行员j配合。文件最后以2
    个-1 结束。
    «结果输出:
    程序运行结束时,将最佳飞行员配对方案输出到文件output.txt 中。第1 行是最佳飞行
    员配对方案一次能派出的最多的飞机数M。接下来M 行是最佳飞行员配对方案。每行有2
    个正整数i和j,表示在最佳飞行员配对方案中,飞行员i和飞行员j 配对。
    如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。

    问题的实质是对于一个映射A,找出一个包含最多元素的双射,这个双射的映射规则是A的子集。

    比较容易想到加一个源点和汇点使之变为最大流问题。如果没想到会相当难解。

    构图:

    建立源点s到集合A(外籍飞行员)的容量为1的有向边(从源点指向A)

    建立集合B(本土飞行员)到汇点t的容量为1的有向边(从B指向汇点)

    根据题中所给映射建立A到B的容量为1的有向边。

    求最大流的得到的流量即为最大匹配数,走过的边为一组可行解。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #define rep(i,a,b) for(int i=a;i<=b;++i)
     5 using namespace std;
     6 int cap[110][110];
     7 int m,n,s,t;
     8 int a[110];
     9 int flow[110][110];
    10 int p[110];
    11 int ansp[110];
    12 int f=0;
    13 void Input()
    14 {
    15     memset(p,0,sizeof(p));
    16     memset(cap,0,sizeof(cap));
    17     scanf("%d%d",&m,&n);
    18     int x,y;
    19     while(scanf("%d%d",&x,&y)==2&&(x!=-1)&&(y!=-1))
    20     {
    21         cap[x][y]=1;
    22     }
    23     s=0;t=n+1;
    24     rep(i,1,m)
    25     {
    26         cap[s][i]=1;
    27     }
    28     rep(i,m+1,n) cap[i][t]=1;
    29    // printf("n=%d,m=%d
    ",n,m);
    30 }
    31 void work()
    32 {
    33     queue<int> q;
    34     memset(flow,0,sizeof(flow));
    35     for(;;)
    36     {
    37         memset(a,0,sizeof(a));
    38         a[s]=1e10;
    39         q.push(s);
    40         while(!q.empty())
    41         {
    42             int u=q.front();q.pop();
    43             rep(i,0,n+1)
    44             {
    45                // printf("u=%d cap[u][%d]=%d
    ",u,i,cap[u][i]);
    46                 if(!a[i]&&cap[u][i]>flow[u][i])
    47                 {
    48                     p[i]=u;q.push(i);
    49                     a[i]=a[u]<(cap[u][i]-flow[u][i])?a[u]:cap[u][i]-flow[u][i];
    50                    // printf("u=%d i=%d a[i]=%d
    ",u,i,a[i]);
    51                 }
    52             }
    53         }
    54        // printf("f=%d a[t]=%d 
    ",f,a[t]);
    55         if(a[t]==0) break;
    56         for(int j=t;j!=s;j=p[j])
    57         {
    58             flow[p[j]][j]+=a[t];
    59             flow[j][p[j]]-=a[t];
    60             ansp[j]=p[j];
    61         }
    62         f+=a[t];
    63     }
    64 }
    65 void pout()
    66 {
    67     if(f==0) printf("No Solution!");
    68     else
    69     {
    70         printf("%d
    ",f);
    71         rep(i,m+1,n)
    72         {
    73             if(ansp[i])
    74             {
    75                 printf("%d %d
    ",ansp[i],i);
    76             }
    77         }
    78     }
    79 }
    80 int main()
    81 {
    82     freopen("air3.in","r",stdin);
    83     //freopen("a.out","w",stdout);
    84     Input();
    85     work();
    86     pout();
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    当你开始学习编程时,你最希望知道什么?我想起来的只有27件事!
    神父说,要有光,要有码农,于是十大天神创造了宏大的编程界!
    我今天就要说HTML它就是一门编程语言!只有外行才说它是超文本标记语言!
    【源码分享】用C++实现通讯录管理系统!功能齐全,实属精品!
    虎牙员工自曝被公司HR带着五个人抬出公司扔到门外!虎牙回应:他简历造假!
    C与C++的互相调用!就像大学宿舍一样,我用你的,你用我的!
    为什么你的简历总会石沉大海!一定要真实,切勿造假!
    Python3列表
    Python3元组
    线程回收
  • 原文地址:https://www.cnblogs.com/zhixingr/p/6916899.html
Copyright © 2020-2023  润新知