poj1459多源点多汇点最大流

题目链接:http://poj.org/problem?id=1459

题意:有许多发电厂,需求电的地方(就说耗电场吧)和一些中转站,要求出各个耗电场耗电之和,并使之最大。其中边上的权值为能流通的最大电量。

题目解析:这道题目也是很简单的最大流题目,只需要添加一个总的源点和一个总的汇点,然后从总源点到子源点边上的权值为子源点的发电量,从汇点到总汇点边上的权值为子汇点的需求电量。就转化成了单源点单汇点的最大流问题了。刚学网络流,不成熟的SAP算法,代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define MAXN  205
#define INS 0xfffffff
#define clr(arr) memset(arr,0,sizeof(arr))

int map[MAXN][MAXN];
int cate[MAXN],index[MAXN],gap[MAXN];
int pre[MAXN],q[MAXN];
bool vis[MAXN],flag;
int minres;

void init_gap_bfs(int n){
	int v,start,end,size = 100; 
	start = end = 0; index[0] = 1; clr(vis); clr(q);
	q[start] = n; vis[n] = true; end++;
	while(start != end){
		v = q[start]; 
		for(int i = 0;i <= n;++i){
			if((!vis[i] ) && map[i][v] > 0){
				vis[i] = true;
				gap[i] = gap[v] + 1;
				index[ gap[i] ]++;
				q[end] = i; end = (end+1)%size;
			}
		}
		start = (start+1)%size;
	}
}

bool dfs(int k,int n){
	int m = minres;
	for(int i = 0;i <= n;++i)
		if(gap[k] - gap[i] ==1 && map[k][i] > 0){
			pre[i] = k; minres = min(minres,map[k][i]);
			if(i == n || dfs(i,n)) return true;
			minres = m;
		}
	index[ gap[k] ]--; index[ gap[k]+1 ]++; 
	if(index[ gap[k] ] == 0)   flag = true;
	gap[k] += 1; 
	return false;
}

int SAP(int b,int n){
	flag = false;
	int maxflow = 0;
	while(!flag){ 
		clr(pre); pre[0] = -1; minres = INS;
		if(!dfs(b,n)) continue; 
		int i = n; maxflow += minres;
		while(pre[i] != -1){
			map[ pre[i] ][i] -= minres; 
			map[i][ pre[i] ] += minres;
			i = pre[i];
		}
	}   return maxflow;
}

int main()
{
	//freopen("1.txt","r",stdin);
	int n,np,nc,m,b,e,v,p;
	while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
		clr(cate); clr(map); clr(index); clr(gap);
		for(int i = 0;i < m;++i){
			scanf(" (%d,%d)%d ",&b,&e,&v);
			b++; e++;
			map[b][e] += v;
		}
		for(int i = 0;i < np + nc;++i){
			scanf(" (%d)%d ",&p,&v);  p++; 
			if(i < np) cate[p] += v;
			else cate[p] -=v;
		}
		for(int i =1;i <= n;++i){
			if(cate[i] > 0) map[0][i] = cate[i];
			if(cate[i] < 0) map[i][n+1] = -cate[i];
		}
		init_gap_bfs(n+1);
		printf("%d\n",SAP(0,n+1));
	}
	return 0;
}

下面是用间隙优化和弧优化的代码,不过弧优化没写好,每次当从k点找不到增广路的时候,更新从k点到汇点的距离,是自加1,不是找所有孩子里汇点最近的加1,不知道怎么处理的,提交结果竟然时间一点也没减少。。。。可能是没用邻接表存边的关系吧,参考代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define MAXN  205
#define INS 0xfffffff
#define clr(arr) memset(arr,0,sizeof(arr))

int map[MAXN][MAXN];
int cate[MAXN],index[MAXN],gap[MAXN];
int pre[MAXN],q[MAXN],stck[MAXN];
bool vis[MAXN],flag;
int minres,top;

void init_gap_bfs(int n){
	int v,start,end,size = 100; 
	start = end = 0; index[0] = 1; clr(vis); clr(q);
	q[start] = n; vis[n] = true; end++;
	while(start != end){
		v = q[start]; 
		for(int i = 0;i <= n;++i){
			if((!vis[i] ) && map[i][v] > 0){
				vis[i] = true;
				gap[i] = gap[v] + 1;
				index[ gap[i] ]++;
				q[end] = i; end = (end+1)%size;
			}
		}
		start = (start+1)%size;
	}
}

bool dfs(int k,int n){
	int m = minres,minn = INS;
	for(int i = 0;i <= n;++i){
		if(gap[k] - gap[i] ==1 && map[k][i] > 0){
			pre[i] = k; minres = min(minres,map[k][i]);
			if(i != n)  stck[++top] = i;
			if(i == n || dfs(i,n)) return true;
			minres = m;
		}
	}
	index[ gap[k] ]--; 
	index[ gap[k]+1 ]++;    
	if(index[ gap[k] ] == 0)   flag = true;
	gap[k] += 1; top--;
	return false;
}

int SAP(int b,int n){
	flag = false; top = 0;
	int maxflow = 0; stck[top] = b;
	while(!flag){ 
		clr(pre); pre[0] = -1; minres = INS;
	    if(top < 0) top = 0;
		if(!dfs(stck[top],n))   continue;
		int i = n; maxflow += minres;
		while(pre[i] != -1){
			map[ pre[i] ][i] -= minres; 
			map[i][ pre[i] ] += minres;
			i = pre[i];
		}
		top = 0;
	}   return maxflow;
}

int main()
{
	//freopen("1.txt","r",stdin);
	int n,np,nc,m,b,e,v,p;
	while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
		clr(cate); clr(index); clr(gap); clr(stck);
		memset(map,-1,sizeof(map));
		for(int i = 0;i < m;++i){
			scanf(" (%d,%d)%d ",&b,&e,&v);
			b++; e++;
			if(map[b][e] == -1) map[b][e] = 0;
			map[b][e] += v;
		}
		for(int i = 0;i < np + nc;++i){
			scanf(" (%d)%d ",&p,&v);  p++; 
			if(i < np) cate[p] += v;
			else cate[p] -=v;
		}
		for(int i =1;i <= n;++i){
			if(cate[i] > 0) map[0][i] = cate[i];
			if(cate[i] < 0) map[i][n+1] = -cate[i];
		}
		init_gap_bfs(n+1);
		printf("%d\n",SAP(0,n+1));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值