本博客会随着后续刷题不断更新。
网络流属于图论一部分,可以解决二分图匹配等问题。
网络流图的特点为,有且仅有一个入度为0的点,并且有且仅有一个出度为0的点,且任意两点之间仅存在一条单向边。通常采用Dinic法,每次bfs搜索路径,若查询到则不断增广路径。
时间复杂度:在普通图下,时间复杂度$O(V^{2}E)$,在二分图中时间复杂度$O(\sqrt{V}E)$。
贴上网络流模板,这边采用邻接表建图。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair <int,int> pii; #define rep(i,x,y) for(int i=x;i<y;i++) #define rept(i,x,y) for(int i=x;i<=y;i++) #define per(i,x,y) for(int i=x;i>=y;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define de(x) cout<< #x<<" = "<<x<<endl #define dd(x) cout<< #x<<" = "<<x<<" " #define mes(a,b) memset(a,b,sizeof a) const ll inf=1e18; const int N=500010,M=300010;//N点数,M边数 int head[N],ver[M],edge[M],Next[M],d[N]; int n,m,s,t,tot,maxflow; queue<int> q; void add(int x,int y,int z)//x到y建长度z单向边 { ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;//邻接表建边 ver[++tot]=x;edge[tot]=0,Next[tot]=head[y],head[y]=tot; } bool bfs()//判断是否有增广路 { mes(d,0); while(!q.empty()) q.pop(); q.push(s); d[s]=1; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x];i;i=Next[i]) if(edge[i]&& !d[ver[i]]) { q.push(ver[i]); d[ver[i]]=d[x]+1; if(ver[i]==t) return 1; } } return 0; } int dinic(int x,ll flow) { if(x==t) return flow; int rest=flow,k; for(int i=head[x];i&&rest;i=Next[i]) { if(edge[i]&&d[ver[i]]==d[x]+1) { k=dinic(ver[i],min(rest,edge[i])); if(!k) d[ver[i]]=0; edge[i]-=k; edge[i^1]+=k; rest-=k; } } return flow-rest; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n>>m;//n为点数,m为边数 cin>>s>>t;//s起点,t终点 tot=1; rep(i,0,m) { int x,y,c; cin>>x>>y>>c; add(x,y,c); } int flow=0; while(bfs()) while(flow=dinic(s,inf)) maxflow+=flow; cout<<maxflow<<"\n"; return 0; }
经典例题:飞行员配对问题https://www.luogu.org/problem/P2756
只需要将外国飞行员和源点相连,英国飞行员和终点相连,然后外国飞行员和英国飞行员建一条边权为1的边即可。
贴上洛谷2756AC代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair <int,int> pii; #define rep(i,x,y) for(int i=x;i<y;i++) #define rept(i,x,y) for(int i=x;i<=y;i++) #define per(i,x,y) for(int i=x;i>=y;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define de(x) cout<< #x<<" = "<<x<<endl #define dd(x) cout<< #x<<" = "<<x<<" " #define mes(a,b) memset(a,b,sizeof a) const ll inf=1e18; const int N=205,M=200000; int head[N],ver[M],edge[M],Next[M],d[N]; int n,m,s,t,tot,maxflow; queue<int> q; void add(int x,int y,int z) { ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot; ver[++tot]=x;edge[tot]=0,Next[tot]=head[y],head[y]=tot; } bool bfs() { mes(d,0); while(!q.empty()) q.pop(); q.push(s); d[s]=1; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x];i;i=Next[i]) if( edge[i] && !d[ver[i]] ) { q.push(ver[i]); d[ver[i]]=d[x]+1; if(ver[i]==t) return 1; } } return 0; } int dinic(int x,ll flow) { if(x==t) return flow; int rest=flow,k; for(int i=head[x];i&&rest;i=Next[i]) { if(edge[i]&&d[ver[i]]==d[x]+1) { k=dinic(ver[i],min(rest,edge[i])); if(!k) d[ver[i]]=0; edge[i]-=k; edge[i^1]+=k; rest-=k; } } return flow-rest; } int main() { ios::sync_with_stdio(false); cin.tie(0); mes(head,0); cin>>n>>m; s=0,t=n+m+1; tot=1; int x,y; while(cin>>x>>y) { if(x==-1&&y==-1) break; add(x,y,1); } rept(i,1,n) add(s,i,1); rept(i,n+1,n+m) add(i,t,1); int flow=0; while(bfs()) while(flow=dinic(s,inf)) maxflow+=flow; if(!maxflow) { cout<<"No Solution!\n"; return 0; } cout<<maxflow<<"\n"; for(int i=1;i<=n;i++) { for(int j=head[i];j;j=Next[j]) { if( j%2==0&&!edge[j] ) { cout<<i<<" "<<ver[j]<<"\n"; } } } return 0; }
原文:https://www.cnblogs.com/FZUzyz/p/11656547.html