题目链接: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 }
匈牙利算法
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 }