poj 1273 & hdu 1532 Drainage Ditches(最大流 )EK,dinic模板

31 篇文章 0 订阅
28 篇文章 0 订阅

第一发网络流纪念下~~~

因为这里e和v都差不多,所以EK和dinic跑出来的时间差不多。纠结的是如何把邻接矩阵换成邻接表的..

EK邻接矩阵写法:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<algorithm>

using namespace std;

typedef __int64 ll;

const int N = 205;

ll a[N][N];
int pre[N];
int vis[N];
queue<int> q;
int n, m;

ll EK()
{
	while( !q.empty() )
		q.pop();
	memset(vis, 0, sizeof( vis ));
	memset(pre, 0, sizeof( pre ));
	bool ok = 0;
	vis[1] = 1;
	q.push(1);
	while( !q.empty() )//用bfs寻找一条源到汇的可行路径
	{
		int u = q.front();
		q.pop();
		for( int i = 1; i <= m; i++ )
		{
			if( !vis[i] && a[u][i] > 0 )
			{
				vis[i] = 1;
				pre[i] = u;
				if( i == m )
				{
					ok = 1;
					break;
				}
				else
					q.push(i);
			}
		}
		if( ok )
			break;
	}
	if( !ok )
		return 0;
	ll minflow = 99999999;
	int now = m;
	while( pre[now] )//寻找源到汇路径上容量最小的边,其容量就是此次增加的总流量
	{
		minflow = min(minflow, a[pre[now]][now]);
		now = pre[now];
	}
	now = m;
	while( pre[now] )//沿此路径添加反向边,同时修改路径上每条边的容量
	{
		a[pre[now]][now] -= minflow;
		a[now][pre[now]] += minflow;
		now = pre[now];
	}
	return minflow;
	
	
}

int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		memset(a, 0, sizeof( a ));
		int u, v;
		ll w;
		while(n--)
		{
			scanf("%d%d%I64d", &u, &v, &w);
			a[u][v] += w;
		}
		ll ans = 0, tmp;
		while( tmp = EK() )
			ans += tmp;
		printf("%I64d\n", ans);
	}
	return 0;
} 

EK邻接表写法:

//http://www.xuebuyuan.com/zh-tw/1555201.html
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<algorithm>

using namespace std;

typedef __int64 ll;

const int N = 205;
const int inf = 0x3f3f3f3f;

struct node{
	int v, nxt;
	ll w;
}e[N*2];

int head[N];
queue<int> q;
int vis[N];
int pre[N];
int re[N];//因为使用邻接表之后唯一不确定的就是边的编号记录到达当前点的边的编号,使用时直接edge[re[x]].w就好了,
int n, m;
int cnt;

void init()
{
	memset(head, -1, sizeof( head ));
	cnt = 0;
}

void add( int u, int v, ll w )
{
	e[cnt].w = w;
	e[cnt].v = v;
	e[cnt].nxt = head[u];
	head[u] = cnt++;
	
	e[cnt].w = 0;
	e[cnt].v = u;
	e[cnt].nxt = head[v];
	head[v] = cnt++;
}

ll EK()
{
	while( !q.empty() )
		q.pop();
	memset( vis, 0, sizeof( vis ));
	memset( pre, 0, sizeof( pre ));
	bool ok = 0;
	q.push(1);
	vis[1] = 1;
	while( !q.empty() )
	{
		int u = q.front();
		q.pop();
		for( int i = head[u]; ~i; i = e[i].nxt )
		{
			int to = e[i].v;
			if( !vis[to] && e[i].w > 0 )
			{
				vis[to] = 1;
				pre[to] = u;
				re[to] = i;
				if( to == m )
				{
					ok = 1;
					break;
				}
				else
					q.push(to);
			}
		}
		if( ok )
			break;
	}
	if( !ok )
		return 0;
	ll minflow = inf;
	int now = m, tmp;
	while( pre[now] )
	{
		minflow = min( minflow, e[re[now]].w);
		now = pre[now];
	}
	now = m;
	while( pre[now] )
	{
		e[re[now]].w -= minflow;
		e[re[now]^1].w += minflow;
		now = pre[now];
	}
	return minflow;
}

int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		init();
		int u, v;
		ll w, ans = 0, tmp;
		while(n--)
		{
			scanf("%d %d %I64d", &u, &v, &w);
			add(u, v, w);
		}
		while( tmp = EK() )
			ans += tmp;
		printf("%I64d\n", ans);
	}
	return 0;
} 

dinic邻接表写法:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<algorithm>

using namespace std;

typedef __int64 ll;

const int N = 205;
const int inf = 0x3f3f3f3f;

struct node{
	int v, nxt;
	ll w;
}e[N*2];

int head[N];
int dep[N];
queue<int> q;
int n, m;
int cnt;

void init()
{
	memset(head, -1, sizeof( head ));
	cnt = 0;
}

void add( int u, int v, ll w )
{
	e[cnt].w = w;
	e[cnt].v = v;
	e[cnt].nxt = head[u];
	head[u] = cnt++;
}

//bfs建立层次图 
int bfs()
{
	memset(dep, 0, sizeof( dep ));
	dep[1] = 1;
	while( !q.empty() )
		q.pop();
	q.push(1);
	while( !q.empty() )
	{
		int u = q.front();
		q.pop();
		if ( u == m )
			return 1;
		for( int i = head[u]; ~i; i = e[i].nxt )
		{
			int to = e[i].v;
			if( !dep[to] && e[i].w )
			{
				dep[to] = dep[u] + 1;
				q.push(to);
			}
		}
	}
	return 0;
}

//当前的节点,minflow 可看成EK里面的增广轨中最小边的权值 
ll dinic(int u, ll minflow)
{
	if( u == m )
		return minflow;
	ll tmp = 0;	//当前获得的flow 
	for( int i = head[u]; ~i; i = e[i].nxt )
	{
		if( e[i].w && dep[e[i].v] == dep[u] + 1 )
		{
			ll flow = dinic( e[i].v, min( e[i].w, minflow - tmp ));	
			//flow 为子节点获得的minflow,而传入的参数为“到达子节点边的剩余容量” 与 
			//“当前边的容量”(因为可能当前的边在这一次增广过程中成为那条满流的边) 
			//简单说就是利用dfs回溯的性质拿子节点获得的minflow更新上一层,而一层一层递归上次就能更新完整张图
			e[i].w -= flow;
			e[i^1].w += flow;	//逆向边更新 
			//更新剩余图 
			tmp += flow;
			if( tmp == minflow )
				return tmp;
		}
	}
	return tmp;
}

ll solve( )
{
	ll tmp = 0;
	while( bfs() )
	{
		tmp += dinic(1, inf);
	}
	return tmp;
}

int main()
{
	while(~scanf("%d%d", &n, &m))
	{
		init();
		int u, v;
		ll w, ans = 0;
		while(n--)
		{
			scanf("%d %d %I64d", &u, &v, &w);
			add(u, v, w);
			add(v, u, 0);//建反向边
		}
		ans = solve();
		printf("%I64d\n", ans);
	}
	return 0;
} 

可参考 http://blog.sina.com.cn/s/blog_ac43e9c3010172l5.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值