[最大流][匈牙利算法] 洛谷 P3386 二分图匹配
题目描述
给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数
输入输出格式
输入格式:
第一行,n,m,e
第二至e+1行,每行两个正整数u,v,表示u,v有一条连边
输出格式:
共一行,二分图最大匹配
输入输出样例
说明
n,m \leq 1000n,m≤1000, 1 \leq u \leq n1≤u≤n, 1 \leq v \leq m1≤v≤m
因为数据有坑,可能会遇到 v>mv>m 的情况。请把 v>mv>m 的数据自觉过滤掉。
算法:二分图匹配
题解
- 看这题目也看着像板题,就是模板题,匈牙利、最大流两种做法
代码1
1 #include <cstdio> 2 #include <iostream> 3 #include <queue> 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 queue<int>Q; 7 struct edge {int to,from,v;}e[2001000]; 8 int n,m,num,cnt,ans,s,t,dis[1010*4],head[1010*4],cur[1010*4]; 9 void insert(int x,int y,int z) { e[++cnt].to=y,e[cnt].from=head[x],e[cnt].v=z,head[x]=cnt; } 10 bool bfs() 11 { 12 for (int i=s;i<=t;i++) dis[i]=0; dis[s]=1; 13 while (!Q.empty()) Q.pop(); Q.push(s); 14 while (!Q.empty()) 15 { 16 int u=Q.front(); Q.pop(); 17 for (int i=head[u];i;i=e[i].from) 18 if (e[i].v&&!dis[e[i].to]) 19 { 20 dis[e[i].to]=dis[u]+1; 21 if (e[i].to==t) return 1; 22 Q.push(e[i].to); 23 } 24 } 25 return 0; 26 } 27 int dfs(int x,int mx) 28 { 29 if (x==t||!mx) return mx; 30 int r=0; 31 for (int &i=cur[x];i;i=e[i].from) 32 if (e[i].v&&dis[e[i].to]==dis[x]+1) 33 { 34 int k=dfs(e[i].to,min(e[i].v,mx-r)); 35 e[i].v-=k; 36 if (i&1) e[i+1].v+=k; else e[i-1].v+=k; 37 r+=k; 38 if (r==mx) break; 39 } 40 return r; 41 } 42 void dinic() 43 { 44 while (bfs()) 45 { 46 for (int i=s;i<=t;i++) cur[i]=head[i]; 47 ans+=dfs(s,inf); 48 } 49 } 50 int main() 51 { 52 scanf("%d%d%d",&n,&m,&num); 53 for (int i=1,x,y;i<=num;i++) 54 { 55 scanf("%d%d",&x,&y); 56 if (x<=n&&y<=m) insert(x,y+n,1),insert(y+n,x,0); 57 } 58 for (int i=1;i<=n;i++) insert(0,i,1),insert(i,0,0); 59 for (int i=1;i<=m;i++) insert(n+i,n+m+1,1),insert(n+m+1,n+i,0); 60 s=0,t=n+m+1,dinic(); 61 printf("%d",ans); 62 }
代码2
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 int n,m,num,ans,cnt,head[1010],p[1010]; 6 bool a[1010][1010],visit[1010]; 7 int xyl(int x) 8 { 9 for (int i=1;i<=n;i++) 10 if (a[x][i]==true&&visit[i]==0) 11 { 12 visit[i]=1; 13 if (p[i]==0||xyl(p[i])) 14 { 15 p[i]=x; 16 return 1; 17 } 18 } 19 return 0; 20 } 21 int main() 22 { 23 scanf("%d%d%d",&n,&m,&num); 24 for (int i=1,x,y;i<=num;i++) 25 { 26 scanf("%d%d",&x,&y); 27 if (x<=n&&y<=m) a[x][y]=1; 28 } 29 for (int i=1;i<=n;i++) memset(visit,0,sizeof(visit)),ans+=xyl(i); 30 printf("%d",ans); 31 }