网络流模板
网络流模板
技巧
-
$ \begin{array}{c}
\left | f+f' \right | = \left | f \right | +\left | f' \right |
\end{array}$
所以,当可行流的残余网络有可行流,原网络的可行流一定不是最大流 -
对于任何一个可行解,都对应一个可行流 并且 对于任何一个可行流,都对应一个可行解
-
如果限制流的距离,分层图
-
如果流网络要附加信息,可以考虑乘上一个常数 \(P\),然后再加上附加数据,即\(xP+y\),只要\(P>y\),结果就不会对原有数据造成影响,同时也能求出附加数据的 \(最大/小\) 值,详见这道题
模板
网络最大流
Dinic算法
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int s=0,t=MX_N-1;
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
for(int i=0;i<MX_N;i++) cur[i]=head[i],dist[i]=-1;
queue<int > qu;qu.push(s);dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(flow==left) dist[now]=-1;
return flow-left;
}
int dinic(){
int sum=0;
while(bfs()){
sum+=dfs(s,INF);
}
return sum;
}
signed main(){
memset(head,-1,sizeof(head));
//=======================================================
//=======================================================
return 0;
}
最小费用最大流
EK(Spfa)
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
int to,next;
int w,cost;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
node& it=edge[edge_cnt];
it.cost=c;it.next=head[x];it.w=w;it.to=y;
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w,int c){
Add(x,y,w,c),Add(y,x,0,-c);
}
int s=0,t=MX_N-1;
int pre[MX_N]={0},lim[MX_N]={0},dist[MX_N]={0};
bool vis[MX_N]={0};
bool spfa(){
memset(lim,0,sizeof(lim));memset(dist,INF,sizeof(dist));memset(vis,0,sizeof(vis));
queue<int >qu;
qu.push(s);lim[s]=INF,vis[s]=1,dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();vis[now]=0;
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w,cost=edge[i].cost;
if(w&&dist[to]>dist[now]+cost){
dist[to]=dist[now]+cost;
pre[to]=i;
lim[to]=min(lim[now],w);
if(!vis[to]){
qu.push(to);
vis[to]=1;
}
}
}
}
return lim[t]>0;
}
void EK(int &flow,int &cost){
flow=cost=0;
while(spfa()){
flow+=lim[t];
cost+=lim[t]*dist[t];
for(int i=t;i!=s;i=edge[pre[i]^1].to){
edge[pre[i]].w-=lim[t];
edge[pre[i]^1].w+=lim[t];
}
}
}
signed main(){
memset(head,-1,sizeof(head));
//=======================================
//=======================================
return 0;
}
费用流究极无敌超级加倍PLUS版之传说最快最变态费用流——网络单纯形算法
#include<bits/stdc++.h>
using namespace std;
const long long MX_N=5e5+500,MX_M=5e6+500,INF=0x3f3f3f3f3f3f3f3f;
struct node{
long long from,to,w,cost,next;
} edge[MX_M];
long long head[MX_N]={0},edge_cnt=1;
inline void Add(long long x,long long y,long long w,long long cost){
edge[++edge_cnt]=(node){x,y,w,cost,head[x]};
head[x]=edge_cnt;
}
inline void add(long long from,long long to,long long w,long long cost){
Add(from,to,w,cost);
Add(to,from,0,-cost);
}
long long piCache[MX_N]={0},fa[MX_N]={0},fe[MX_N]={0},circle[MX_N]={0},mark[MX_N]={0},curtime=1;
// 随机一棵生成树初始化
void init_tree(long long from,long long fi){
fe[from]=fi;
fa[from]=edge[fi].from;
mark[from]=1;
for(long long i=head[from];i;i=edge[i].next){
long long to=edge[i].to;
//不过这里mark就判重用的
if(mark[to]||edge[i].w==0)continue;
init_tree(to,i);
}
}
inline long long pi(long long x){
if(mark[x]==curtime)return piCache[x];
mark[x]=curtime;
piCache[x]=pi(fa[x])+edge[fe[x]].cost;
return piCache[x];
}
//沿着e在生成树上形成的环推送流
long long pushFlow(long long e){
//向上标记法求lca,够暴力
long long rt=edge[e].from,lca=edge[e].to;
curtime++;
long long ccnt=0;
while(rt){
mark[rt]=curtime;
rt=fa[rt];
}
while(mark[lca]!=curtime){
mark[lca]=curtime;
lca=fa[lca];
}
//找到被替换的(省域流量最小的)边,记录环上最小剩余流量
long long minflow=edge[e].w,p=2,del_u=0;
for(long long from=edge[e].from;from!=lca;from=fa[from]){
circle[++ccnt]=fe[from];
if(edge[fe[from]].w<minflow){
minflow=edge[fe[from]].w;
del_u=from;
p=0;
}
}
for(long long from=edge[e].to;from!=lca;from=fa[from]){
long long ne=fe[from]^1;
circle[++ccnt]=ne;
if(edge[ne].w<minflow){
minflow=edge[ne].w;
p=1;
del_u=from;
}
}
circle[++ccnt]=e;
//沿着环推送流量
long long cost=0;
for(long long i=1;i<=ccnt;i++){
cost+=edge[circle[i]].cost*minflow;
edge[circle[i]].w-=minflow;
edge[circle[i]^1].w+=minflow;
}
//如果最小的就是当前边就不用加到树上了
if(p==2)return cost;
//把边加入树上,翻转一条链
long long from=edge[e].from,to=edge[e].to;
if(p==1)swap(from,to);
long long last_e=e^p,last_u=to;
while(last_u!=del_u){
last_e^=1;
mark[from]--; // 设置这条链上的信息过期
swap(fe[from],last_e);
long long nu=fa[from];
fa[from]=last_u;
last_u=from;
from=nu;
}
return cost;
}
long long s=0,t=MX_N-1;
//总算法
void simplex(long long &flow,long long &cost){
flow=cost=0;
add(t,s,INF,-INF);
init_tree(t,0);
mark[t]=++curtime;
fa[t]=0;
//反复执行
bool running=true;
while(running){
running=false;
for(long long i=2;i<=edge_cnt;i++){
if(edge[i].w&&edge[i].cost+pi(edge[i].from)-pi(edge[i].to)<0){
cost+=pushFlow(i);
running=true;
}
}
}
//flow在每次直接累加是错的,会把正反的都算上,直接根据一开始加的那条边算
flow=edge[edge_cnt].w;
cost=cost+flow*INF;
return ;
}
long long ans[MX_N]={0};
signed main(){
//=======================================
long long flow,cost;simplex(flow,cost); //注意edge_cnt从2开始
//=======================================
return 0;
}
无源汇上下界可行流
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100,INF=0x3f3f3f3f;
struct node{
int next,to,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int s=0,t=MX_N-1;
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
for(int i=0;i<MX_N;i++) dist[i]=-1,cur[i]=head[i];
queue<int >qu;qu.push(s);dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==-1&&w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(w,left));
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
left-=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
int dinic(){
int sum=0;
while(bfs()) sum+=dfs(s,INF);
return sum;
}
//=============================================
struct no{
int x,y,dow,upp;
}ed[MX_M<<1];
int ed_cnt=0;
inline void add_ed(int x,int y,int dow,int upp){
ed[ed_cnt++]={x,y,dow,upp};
}
int in[MX_N]={0};
int build_graph(){
int sum=0;
for(int i=0;i<ed_cnt;i++){
add(ed[i].x,ed[i].y,ed[i].upp-ed[i].dow);
in[ed[i].x]-=ed[i].dow;
in[ed[i].y]+=ed[i].dow;
}
for(int i=0;i<MX_N;i++){
if(in[i]<0){
add(i,t,-in[i]);
}
else if(in[i]>0){
add(s,i,in[i]);sum+=in[i];
}
}
return sum;
}
signed main(){
memset(head,-1,sizeof(head));
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);
add_ed(a,b,c,d);
}
int sum=build_graph();
if(dinic()!=sum) return puts("NO"),0;
printf("YES\n");
for(int i=0;i<m*2;i+=2){
printf("%d\n",edge[i^1].w+ed[i/2].dow);
}
return 0;
}
有源汇上下界最 大/小 流
#include<bits/stdc++.h>
using namespace std;
const int MX_M=11000,MX_N=310;
struct node{
int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.next=head[x],i.to=y;
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(int s,int t){
memset(dist,-1,sizeof(dist));
queue<int > qu;qu.push(s);dist[s]=0;
while (!qu.empty())
{
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow,int t){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w)
{
int cur_flow=dfs(to,min(left,w),t);
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
int n;
int dinic(int s,int t){
int ans=0;
while(bfs(s,t)){
for(int i=1;i<=n;i++) cur[i]=head[i];
ans+=dfs(s,0x3f3f3f3f,t);
}
return ans;
}
int flw[MX_N]={0};
signed main(){
memset(head,-1,sizeof(head));
int input_n,m,s,t;
int S,T;int sum=0;
scanf("%d%d%d%d",&input_n,&m,&s,&t);
S=input_n+1,T=input_n+2,n=T;
add(t,s,0x3f3f3f3f);
for(int i=1;i<=m;i++){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);add(a,b,d-c);
flw[a]+=c,flw[b]-=c;
}
for(int i=1;i<=input_n;i++){
if(flw[i]<0){
add(S,i,-flw[i]);sum-=flw[i];
}
else{
add(i,T,flw[i]);
}
}
int sn=dinic(S,T);
int ans=edge[1].w;
edge[0].w=0;edge[1].w=0;
if(sn!=sum){
printf("No Solution");return 0;
}
ans+=dinic(s,t); //最小流改为 ans-=dinic(s,t);
cout<<ans;
return 0;
}

浙公网安备 33010602011771号