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

从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
原文地址:https://www.cnblogs.com/zhixingr/p/6916899.html