学习笔记第三十节:zkw费用流

版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/84386288

正题

      这个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();
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/84386288