學習筆記第三十節:zkw費用流
阿新 • • 發佈:2018-12-04
正題
這個zkw大神非常6,把兩種很顯然的網路流演算法結合了起來。
zkw費用流=EK費用流+Dinic最大流
對,你沒有看錯。
我們回憶一下Dinic找增廣路的過程,是不是一遇到一條可以走的邊就走,走出來一條源點到匯點的一條可行的路徑,就可以了。
我們再回憶一下EK費用流的過程,是不是先跑SPFA,使其找出一條流量不為0的,最小費用的,從源點到匯點的,路徑。
這條路也是可行的,那麼我們每次做SPFA只能增廣一條路徑。
剩下SPFA剩下的資料就沒有用了?
結合一下,我們當前增廣的路徑肯定在源點的最短路圖上。這個結論是不是挺顯然的。
因為一條不在最短路圖上的路徑肯定費用沒有最短路圖上的費用小。
這個最短路圖也是可以一次SPFA跑出來的。(正著跑和反著跑其實都是一個道理)。
這時,我們順著最短路圖來做一次Dinic找增廣路就可以了。
並且,我們再做SPFA的時候,順便分一下層,那就可以很好的利用Dinic的分層優化。
SPFA的SLF優化也可以加上。
優點大於缺點:在資料量較大的時候,特別是增廣路較多,較長的時候,特別有優勢。
缺點不說了吧,就是資料小的時候常數大。這個是無法避免的。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
int n,m,begin,end;
struct edge{
int x,y,next,c,cos;
}s[100010];
int first[5010],len=1;
deque<int> f;
bool tf[5010];
int d[5010],ty[5010];
void ins(int x,int y,int c,int cos){
len++;s[len]=(edge){x,y,first[x],c,cos};first[x]=len;
len++;s[len]=(edge){y,x,first[y],0,-cos};first[y]=len;
}
bool SPFA(){
memset(tf,false,sizeof(tf));
memset(ty,0,sizeof(ty));
memset(d,63,sizeof(d));d[begin]=0;ty[begin]=1;
f.push_back(begin);tf[begin]=true;
while(!f.empty()){
int x=f.front();f.pop_front();tf[x]=false;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(d[y]>d[x]+s[i].cos && s[i].c>0){
d[y]=d[x]+s[i].cos;
ty[y]=ty[x]+1;
if(!tf[y]){
tf[y]=true;
if(!f.empty() && d[y]<d[f.front()]) f.push_front(y);
else f.push_back(y);
}
}
}
}
return d[end]!=d[n+1];
}
int dfs(int x,int t,int&flow,int&cost){
tf[x]=true;
if(x==end) {
flow+=t;
return t;
}
int tot=0,my=0;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(t==tot) break;
if(d[x]+s[i].cos==d[y] && ty[x]+1==ty[y] && s[i].c>0){
tot+=(my=dfs(y,min(t-tot,s[i].c),flow,cost));
cost+=my*s[i].cos;
s[i].c-=my;s[i^1].c+=my;
}
}
return tot;
}
void MCMF(){
int flow=0,cost=0;
while(SPFA()){
tf[end]=true;
while(tf[end]){
memset(tf,false,sizeof(tf));tf[begin]=true;
dfs(begin,1e9,flow,cost);
}
}
printf("%d %d\n",flow,cost);
}
int main(){
scanf("%d %d %d %d",&n,&m,&begin,&end);
int x,y,c,cos;
for(int i=1;i<=m;i++){
scanf("%d %d %d %d",&x,&y,&c,&cos);
ins(x,y,c,cos);
}
MCMF();
}