暑期总结——网络流



一张图中每条边都有同一时间能承载的最大数据量,求最大网络流即求从起点到终点同一时间能运输的最大数据量。

找到一条从起点到终点的路,那么这条路上运输的数据量为权值最小的边的权值,然后再依次做下去,但这样过早地阻塞了后面的流,会造成无法得到最优解。解决的方法是添加一条反向边,如果边<u,v>流过了k,那么反向边<v,u>的权值即为n-k;这样就形成了一张残余网络;

Dinic算法:^_^据说^_^从终点到起点所经过的边的数量越少,那么效率就越高。所以说可以先做一遍BFS,找出每一个点的层数,然后在DFS时就只做自己下一层的点;找出一条路上的最小值后更新每个点的正边(减少)和反边(增加);



Dinic代码:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int flag[210],dis[210],n,m,num=2,fir[210],dl[500],head,tail;
struct ppp{
	int go,nxt,val;
}e[500];
void ini(){
	num=2; head=0; tail=1;
	memset(e,0,sizeof(e));
	memset(fir,0,sizeof(fir));
	memset(dl,0,sizeof(dl));
	memset(flag,0,sizeof(flag));
}
void add(int a,int b,int c,int rc){
	e[num].go=b; e[num].val=c;
	e[num].nxt=fir[a]; fir[a]=num++;
	e[num].go=a; e[num].val=rc;
	e[num].nxt=fir[b]; fir[b]=num++;
}
int BFS(){
	queue<int> q;
	q.push(1);
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=fir[u];i;i=e[i].nxt){
			int v=e[i].go;
			if(e[i].val>0 && dis[v]==0x3f3f3f3f){
				dis[v]=dis[u]+1;
				q.push(v);
			}
		}
	}
	return dis[n]<0x3f3f3f3f;
}
int min(int x,int y){
	if(x>y) return y; return x;
}
int dfs(int s,int f){
	if(s==n) return f;
	for(int i=fir[s];i;i=e[i].nxt){
		int t=e[i].go,c=e[i].val;
		if(dis[t]==dis[s]+1 && c>0){
			int flow=dfs(t,min(f,c));
			if(flow){
				e[i].val-=flow;
				e[i^1].val+=flow;
				return flow;
			}
		} 
	}
	return 0;
}
int max_ans(int s){
	int ans=0;
	while(BFS()){
		int flow;
		while(flow=dfs(s,0x3f3f3f3f)){
			ans+=flow; 
		}
	}
	return ans;
}
int main(){
	freopen("水渠测试数据.txt","r",stdin);
	while(scanf("%d%d",&m,&n)!=EOF){
		ini();
		int i,j;
		for(i=1;i<=m;i++){
			int a,b,c; scanf("%d%d%d",&a,&b,&c);
			add(a,b,c,0);
		}
		printf("%d\n",max_ans(1));
	}
}

!!QUESTION!!:

求大神回答这两种写法有什么不同,都可以AC,但在不同的题中效率不一样:

1:

int dfs(int s,int f){
	if(s==n) return f;
	for(int i=fir[s];i;i=e[i].nxt){
		int t=e[i].go,c=e[i].val;
		if(dis[t]==dis[s]+1 && c>0){
			int flow=dfs(t,min(f,c));
			if(flow){
				e[i].val-=flow;
				e[i^1].val+=flow;
				return flow;
			}
		} 
	}
	return 0;
}
2:
int dfs(int s,int f){
	int p=f;
	if(s==n) return f;
	for(int i=fir[s];i;i=e[i].nxt){
		int t=e[i].go,c=e[i].val;
		if(dis[t]==dis[s]+1 && c>0){
			int flow=dfs(t,min(f,c));
				e[i].val-=flow;
				e[i^1].val+=flow;
				f-=flow;
		} 
	}
	return p-f;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值