二分图与网络流 带权二分图的最大匹配
二分图与网络流 带权二分图的最大匹配
在某书上偶然发现,二分图和网络流是有联系的,在子图u中建立超级源点,在子图v中建立超级汇点,源点到u和汇点到v的每条边容量设为1,u和v中的边的容量也设为1,求出最大流也就是原二分图的最大匹配了。
而求带权二分图的最大匹配也就很容易了,将u和v的权值设为容量,仍然建立超级源点和超级汇点转为网络流解决即可。
真是一切皆可网络流啊。。。
然而。。。
下面是xdoj1048,二分图模版测试题,匈牙利算法649ms,Hotcroft_Carp算法155ms,而转为网络流用Edmonds_Karp算法超时。。看来网络流还没学到更高级的算法之前还是不要随便将二分图的题目转为网络流了,如果是带权最大匹配就可以尝试下。
http://acm.xidian.edu.cn/problem.php?id=1048
匈牙利算法:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> using namespace std; typedef long long ll; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); int uN,vN; vector<int> G[maxn]; int link[maxn]; bool vis[maxn]; int m; bool dfs(int u) { for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(!vis[v]){ vis[v]=1; if(link[v]==-1||dfs(link[v])){ link[v]=u; return true; } } } return false; } int hungary() { int res=0; memset(link,-1,sizeof(link)); for(int u=0;u<uN;u++){ memset(vis,0,sizeof(vis)); if(dfs(u)) res++; } return res; } int main() { while(cin>>uN>>vN){ for(int i=0;i<uN;i++) G[i].clear(); cin>>m; while(m--){ int u,v; cin>>u>>v; G[u].push_back(v); } cout<<hungary()<<endl; } return 0; }
Hotcroft_Carp算法:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> using namespace std; typedef long long ll; const int maxn=3100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); int m; vector<int> G[maxn]; int Mx[maxn],My[maxn],Nx,Ny; int dx[maxn],dy[maxn],dis; bool vis[maxn]; bool searchP() { queue<int> q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++){ if(Mx[i]==-1){ q.push(i); dx[i]=0; } } while(!q.empty()){ int u=q.front(); q.pop(); if(dx[u]>dis) break; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(dy[v]==-1){ dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else{ dx[My[v]]=dy[v]+1; q.push(My[v]); } } } } return dis!=INF; } bool dfs(int u) { for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(!vis[v]&&dy[v]==dx[u]+1){ vis[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||dfs(My[v])){ My[v]=u; Mx[u]=v; return true; } } } return false; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()){ memset(vis,0,sizeof(vis)); for(int i=0;i<Nx;i++){ if(Mx[i]==-1&&dfs(i)) res++; } } return res; } int main() { while(cin>>Nx>>Ny){ cin>>m; for(int i=0;i<Nx;i++) G[i].clear(); memset(G,0,sizeof(G)); while(m--){ int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); } cout<<MaxMatch()<<endl; } return 0; }
转为网络流超时的Edmonds_Karp算法:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> using namespace std; typedef long long ll; const int maxn=1200; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); int uN,vN; int m; int cap[maxn][maxn],flow[maxn][maxn]; int s,t; int Edmonds_Karp(int s,int t) { int f=0; int p[maxn],a[maxn]; queue<int> q; memset(flow,0,sizeof(flow)); while(1){ memset(a,0,sizeof(a)); a[s]=INF; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int v=0;v<=t;v++){ if(!a[v]&&cap[u][v]-flow[u][v]>0){ q.push(v); p[v]=u; a[v]=min(a[u],cap[u][v]-flow[u][v]); } } } if(a[t]==0) return f; for(int u=t;u!=s;u=p[u]){ flow[p[u]][u]+=a[t]; flow[u][p[u]]-=a[t]; } f+=a[t]; } } int main() { while(cin>>uN>>vN){ s=uN+vN; t=s+1; cin>>m; memset(cap,0,sizeof(cap)); while(m--){ int u,v; scanf("%d%d",&u,&v); v+=uN; cap[u][v]=1; } for(int u=0;u<uN;u++) cap[s][u]=1; for(int v=uN;v<uN+vN;v++) cap[v][t]=1; cout<<Edmonds_Karp(s,t)<<endl; } return 0; }
没有AC不了的题,只有不努力的ACMER!