POJ 1459 Power Network (多源点/汇点最大流问题)

本文介绍了一种解决电力网络中最大电力传输问题的方法,通过将多源多汇点问题转化为单源单汇点问题,利用Dinic算法求解最大流。文章详细解释了超级源点和超级汇点的概念,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题目大意:对于一个电力网来说,既有发电站,也有用电方,还有输电线路。其中发电站是有限度的,用电方也是有限度的,输电线更是有限度的,所以明显一个网络流问题。先给出线路和限度,再给出用电方,最后后出发电站。

因为是多源点(多个发电站),多汇点(多个用电方),所以需要超级源处理。

多为超级源,就是假设有一个源,连向所有的源点(发电站),其线路容量就是发电站的限度,那么就可以把发电站当做普通点处理。再假设一个超级汇点,那么就可以把所有汇点(用电方)连向这个超级汇点,其线路容量是用电方限度,那么,就变成一个单纯的单源点,单汇点的最大流问题。用dinic便可以解决。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <algorithm>
#define MAX 999999

using namespace std;

int map_[200][200];
int dis[200];

int bfs(int s, int t)
{
	int now;
	memset(dis, -1, sizeof(dis));
	dis[s] = 0;
	queue<int> que;
	que.push(s);

	while (!que.empty())
	{
		now = que.front();
		que.pop();

		for (int i = 0; i <= t; i++)
			if (dis[i] == -1 && map_[now][i] > 0)
			{
				dis[i] = dis[now] + 1;

				que.push(i);
			}
	}

	if (dis[t] != -1)
		return 1;

	return 0;
}

int dinic(int s, int t, int x)
{
	if (s == t)
		return x;

	int tmp = x;
	for (int i = 0; i <= t; i++)
	{
		if (dis[i] == dis[s] + 1 && map_[s][i] > 0)
		{
			int imin = dinic(i, t, min(map_[s][i], x));

			map_[s][i] -= imin;
			map_[i][s] += imin;
			x -= imin;
		}
	}

	return tmp - x;
}

int main()
{
	int n, np, nc, m;
//大意是在一个电力网中有n个节点,其中有np个发电站,nc个消耗点,剩下的为中转站,m条电缆。每条电缆都有传送电力的限制。
	while (~scanf("%d%d%d%d", &n, &np, &nc, &m))
	{
		int i, k;
		int u, v, c;
		memset(map_, 0, sizeof(map_));
		for (i = 0; i < m; i++)
		{
			scanf(" (%d,%d)%d", &u, &v, &c);
			map_[u + 1][v + 1] += c;    //0是超级源点,其他点后移
			// 节点从0到n-1,可以让节点的值+1,然后让0作为超级源点,让n+1作为超级汇点
		}

		for (i = 0; i < np; i++)
		{
			scanf(" (%d)%d", &v, &c);
			map_[0][v + 1] += c;
		}

		for (i = 0; i < nc; i++)
		{
			scanf(" (%d)%d", &u, &c);
			map_[u + 1][n + 1] += c;
		}

		int ans = 0;

		while (bfs(0, n + 1))
			ans += dinic(0, n + 1, MAX);

		printf("%d\n", ans);
	}
	return 0;
}

// Sample Input 
// 2 1 1 2 (0,1)20 (1,0)10 
//         (0)15 (1)20

// 7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7
//         (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5
//         (0)5 (1)2 (3)2 (4)1 (5)4

// Sample Output 
// 15
// 6 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值