最大流&最小费用最大流
求最大流的方法有FF,EK,dinic,dinic最优
dinic算法的核心是对图分层
定义一个节点的“层”\(dis_x\) 为\(x\)到源点\(s\)的距离。可以通过一遍bfs对图分好层
dinic算法规定:每次流水只能从第i层流向第i+1层,不能在同一层流,也不能回流。同时为了反悔,增加了反向边,通常把一组反向边的编号\(i,j\)设为2,3;4,5;6,7,从而可以由e异或1方便地得到它的反向边编号。每当流过一条边时,就把本边限流量-真实流量,反向边流量+真实流量
显然,只有流量为正的边才能流
当有一时刻发现源点汇点不再联通,就无法给图分层,于是算法结束
复杂度\(O(n^2m)\)
#include<bits/stdc++.h> #define int long long using namespace std; const int INF=1e15; int n,m,s,t,p=1; int cur[205],we[10005],dis[205]; queue<int>Q; struct edge { int x,id; }; vector<edge>G[205]; bool bfs(){ memset(dis,0,sizeof(dis)); while(!Q.empty())Q.pop(); Q.push(s);dis[s]=1; while(!Q.empty()){ int now=Q.front();Q.pop(); for(int i=0;i<G[now].size();i++){ int y=G[now][i].x,z=we[G[now][i].id]; if(z&&!dis[y])Q.push(y),dis[y]=dis[now]+1; } } return dis[t]; } int dfs(int x,int in){ if(x==t)return in; int out=0; for(int i=0;i<G[x].size()&∈i++){ int y=G[x][i].x,z=we[G[x][i].id]; if(z&&dis[y]==dis[x]+1){ int los=dfs(y,min(in,z)); we[G[x][i].id]-=los; we[G[x][i].id^1]+=los; in-=los; out+=los; } } if(!out)dis[x]=0; return out; } signed main() { cin>>n>>m>>s>>t; for(int i=1,u,v,w;i<=m;i++){ cin>>u>>v>>w; G[u].push_back((edge){v,++p}); G[v].push_back((edge){u,++p}); we[p^1]=w,we[p]=0; } int ans=0; while(bfs()){//cout<<ans<<endl; ans+=dfs(s,INF); } cout<<ans<<endl; }
贪心,每次寻找s->t的费用最短路,路径上的所有边的流量最小值即为这一次的流量Min,那么这次所消耗的费用Min*(边的费用之和)
同样地,每次-Min后反向边+Min
进行若干次,直到图不连通(无法找到最短路)
最短路可以用dij/spfa
复杂度\(O(nm^2)\)(通常情况下不会达到)
//在这里加o2优化 #include<bits/stdc++.h> #define INF 0x3f3f3f3f #define N 5005 #define M 100005 using namespace std; int n,m,s,t,p=1; struct edge { int u,c,id; }; vector<edge>G[N]; queue<int>Q; int we[M],dis[N],inq[N]; void con(int u,int v,int w,int c,int p){ G[u].push_back((edge){v,c,p}); we[p]=w; } struct nodepre{ int u,id,c; }pre[N]; bool spfa(){ memset(dis,0x3f,sizeof(dis)); dis[s]=0;inq[s]=1;Q.push(s); while(!Q.empty()){ int x=Q.front();Q.pop();inq[x]=0; for(int i=0;i<G[x].size();i++){ int y=G[x][i].u,z=we[G[x][i].id],w=G[x][i].c; if(z&&dis[y]>dis[x]+w){ dis[y]=dis[x]+w; pre[y].u=x,pre[y].id=G[x][i].id,pre[y].c=w; if(!inq[y])inq[y]=1,Q.push(y); } } } return dis[t]!=INF; } int main() { ios::sync_with_stdio(false); cin>>n>>m;s=1,t=n; for(int i=1,u,v,w,c;i<=m;i++){ cin>>u>>v>>w>>c; con(u,v,w,c,++p); con(v,u,0,-c,++p); } int flow=0,ans=0; while(spfa()){ int Min=INF; for(int i=t;i!=s;i=pre[i].u) Min=min(Min,we[pre[i].id]); for(int i=t;i!=s;i=pre[i].u){ we[pre[i].id]-=Min; we[pre[i].id^1]+=Min; ans+=pre[i].c*Min; } flow+=Min; } cout<<flow<<' '<<ans<<endl; }