1. 程式人生 > >學習筆記第三十節:zkw費用流

學習筆記第三十節:zkw費用流

正題

      這個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();
}