学习笔记第三十一节:ISAP

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

正题

      平时我们用的都是Dinic算法,每次bfs之后,我们习惯用dfs来找增广路。时间复杂度是O(n^2*m)。而且有时候很接近上界。

       ISAP给这个Dinic算法带来了许多优化:

    第一个

       I表示的是improved,也就是说我们不用bfs那么多遍,我们可以通过每一次修改分层图的标号h来达到这个目的,怎么修改呢?

       考虑一个点一开始可以到达的点,存在条件h[x]+1=h[y],其他有流量的边但是不可以到达的,说明一定在它之前到达了。

        h[k]<h[x]+1,k表示的是有流量但是不可以到达的点。如果到当前点x的流量不能被分完,那么说明需要更多点来满足到达x的流量。

        这时,我们把h[k]中的最小值+1就可以达到我们的目的,因为总会加到h[x]+1.特别的,当汇点的h等于n+1的时候,退出。(因为肯定有一个点被重复经过了两遍

    第二个

        前项弧优化,就是当x点的流量流完之后,下次过来的时候,可以从上次流量用尽的地方继续流,因为前面的流量必定为0.

       这时我们需要做的就是bfs一遍,然后不断dfs了。

       好像有点麻烦。

     小小的优化和代码简写方法:

       1.我们倒过来bfs,那么h记录的就是到end的最短距离,也就是说,h[x]会被出边的最小的h[y]更新,这时如果我们在x点没有用尽流量,我们需要更多的点,我们就把h[x]++就好了,因为这时不能去到的点一定比h[x]大。(仔细想想为什么

       2.发现断层的时候,也是不行的。我们用一个gap来记录第i层的点有多少个,那么发现第i层的点从有变为没有时,就结束。

       代码比Dinic要简短。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#define inf 2147483647
using namespace std;

int n,m,begin,end;
struct edge{
	int y,next,c;
}s[240010];
int first[10010],len=1,d[10010];
int h[10010];
int gap[10010];
queue<int> f;

void ins(int x,int y,int c){
	len++;
	s[len]=(edge){y,first[x],c};h[x]=first[x]=len;
	len++;
	s[len]=(edge){x,first[y],0};h[y]=first[y]=len;
}

void bfs(){
	++gap[d[end]=1];f.push(end);
	while(!f.empty()){
		int x=f.front();f.pop();
		for(int i=h[x];i!=0;i=s[i].next){
			int y=s[i].y;
			if(d[y]==0) ++gap[d[y]=d[x]+1],f.push(y);
		}
	}
}

int dfs(int x,int t){
	if(x==end) return t;
	int my,tot=0;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(d[x]==d[y]+1 && s[i].c>0){
			my=dfs(y,min(s[i].c,t-tot));
			tot+=my;s[i].c-=my;s[i^1].c+=my;
		}
		if(t==tot) {
			first[x]=i;
			return t;
		}
	}
	if(!(--gap[d[x]])) d[begin]=n+1;
	++gap[++d[x]];first[x]=h[x];
	return tot;
	
}

void Max_Flow(){
	bfs();
	int flow=dfs(begin,inf);
	while(d[begin]<=n) flow+=dfs(begin,inf);
	printf("%d\n",flow);
}

int main(){
	scanf("%d %d %d %d",&n,&m,&begin,&end);
	int x,y,c;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&x,&y,&c);
		ins(x,y,c);
	}
	Max_Flow();
}

       

猜你喜欢

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