网络流学习

昨天学习了网络流,可算弄明白了。把学习过程中看的博客和视频贴一下,大佬们讲的很好了,我就不写了赖得写了
先看基本概念:博客链接这篇文章讲的很好,也讲了许多求最大流的算法,其中最好理解的是EK算法,但是效率不高,Dicnic算法是其改进版,也是竞赛经常用到的算法
如果看完文章之后EK和Dicnic算法没看懂的话,我再贴两个讲解这两个算法的视频
EK:视频链接
Dicnic:1.视频链接2.视频链接
看完这些博客和视频我想你已经弄懂了
写一个板子题练一下板子题HDU Drainage Ditches
EK算法题解:复杂度o(VE^2)
#pragma GCC optimize(2)//算法复杂度是o(NM^2,N是点数,M是边数) 
#include<bits/stdc++.h>//HDUoj  1532 

using namespace std;

typedef long long ll;
#define pi acos(-1.0)
#define e exp(1.0)
typedef pair<ll,ll> pa;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll maxn=220;
ll N,M,G[maxn][maxn],pre[maxn],flow[maxn];
queue<ll>Q;
ll BFS(ll S,ll T){
	while(!Q.empty())
	Q.pop();
	memset(pre,-1,sizeof(pre));
	flow[S]=INF;//flow[u]表示从源点S走到u时的可行流 
//	pre[S]=0;
	Q.push(S);
	while(!Q.empty()){
		ll u=Q.front();
		Q.pop();
		if(u==T)
		break;		
		for(ll v=1;v<=N;v++){
			if(v!=S&&G[u][v]>0&&pre[v]==-1){//pre[v]==-1,说明该点没有被访问过 
				flow[v]=min(flow[u],G[u][v]);
				pre[v]=u;
				Q.push(v);
			}

		}
	}
	if(pre[T]==-1)
	return -1;
	return flow[T];
}
ll EK(ll S,ll T){
	ll delta,maxflow=0; 
	while(1){//不断寻找增广路径和构建残余网络 
		delta=0;//找到一条增广路径,并且增加的可行流为delta 
		delta=BFS(S,T);
		if(delta==-1)//没有找到增广路径的情况,就可以结束了 
		break;
		 
		ll p=T;
		while(p!=S){//更新残余网络 
			G[pre[p]][p]-=delta;
			G[p][pre[p]]+=delta;
			p=pre[p];
		} 
		maxflow+=delta;//更新最大流
	}
	return maxflow;
}
int main()
{
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	while(~scanf("%lld %lld",&M,&N)){
		ll i,j,u,v,w;
		memset(G,0,sizeof(G));
		memset(flow,0,sizeof(flow));
		for(i=1;i<=M;i++){
			scanf("%lld %lld %lld",&u,&v,&w);
			G[u][v]+=w;
		}	
		printf("%lld\n",EK(1,N));
	}	
	return 0;
}

Dicnic算法题解:在普通情况下, DINIC算法时间复杂度为O(V2E) 在二分图中, DINIC算法时间复杂度为O(√VE)
#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define pi acos(-1.0)
#define e exp(1.0)
typedef pair<ll,ll> pa;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll maxn=220;
const ll maxm=220;
ll dep[maxn],head[maxn],cnt=0,N,M,S,T,cur[maxn];//cur[]:当前弧优化 

struct node{
	ll v,w,next;
}edge[maxm<<1];//需要建立反边,所以边的大小的原来的2倍 
void add(ll u,ll v,ll w){
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt++;
	return ;
}
bool BFS(ll S,ll T){//用BFS建立分层图 
	ll i,j;
	for(i=1;i<=N;i++)
	dep[i]=-1;
	dep[S]=0;
	queue<ll>Q;
	Q.push(S);
	while(!Q.empty()){
		ll u=Q.front();
		Q.pop();
		for(i=head[u];~i;i=edge[i].next){
			ll v=edge[i].v,w=edge[i].w;
			if(w&&dep[v]==-1){
				dep[v]=dep[u]+1;
				Q.push(v);
			}
		}
	}
	return dep[T]!=-1;//如果汇点被访问到返回真 
}
ll DFS(ll now,ll fl){//用DFS求增加的流量.fl为源点到这个点的路径上的最小边权 
	ll i,j;
	if(now==T)
	return fl;
	ll f=0;
	for(i=cur[now];~i;i=edge[i].next){//i=cur[now]当前弧优化 
		cur[now]=edge[i].next;
		ll v=edge[i].v,w=edge[i].w;
		if(dep[v]==dep[now]+1&&w){
			ll x=DFS(v,min(w,fl));
			if(x<=0)
			continue;
			edge[i].w-=x;
			edge[i^1].w+=x;
			fl-=x;
			f+=x;
			if(fl<=0)
			break;
		}

	} 
	if(!f)//说明不能再增加流量了,没有可以用的价值 
	dep[now]=-1;//在本次构造增广网的过程中,将不会再考虑该点 
	return f;
}
ll Dinic(ll S,ll T){
	ll res=0;
	while(BFS(S,T)){
		for(ll i=1;i<=N;i++)
		cur[i]=head[i];//当前弧优化的初始化 
		res+=DFS(S,INF);		
	}
	return res;
}
int main()
{
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);

//	scanf("%lld %lld %lld %lld",&N,&M,&S,&T);
	while(~scanf("%lld %lld",&M,&N)){
		memset(head,-1,sizeof(head));
	    cnt=0;	
		ll i,j,u,v,w;
		for(i=0;i<M;i++){
			scanf("%lld %lld %lld",&u,&v,&w);
			add(u,v,w);
			add(v,u,0);//建反边 
		}
		S=1,T=N;
		printf("%lld\n",Dinic(S,T));		
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值