解题报告 之 SOJ3353 Total Flow

本文介绍了一道计算机科学中的经典问题——最大流问题,并通过一个具体的实例展示了如何运用 Dinic 算法求解。博客详细解释了问题背景,即计算从水源到牲口棚的最大供水能力,并给出了简化复杂网络的规则。通过 ASCII 码将节点编号,然后利用 Dinic 算法进行求解,最终得出最大流量。文章提供了完整的 C++ 代码实现,是一篇关于图论和算法实践的教程。
摘要由CSDN通过智能技术生成

解题报告 之 SOJ3353 Total Flow

Description

Time Limit: 2000 MS Memory Limit: 65536 K


The Problem

PROBLEM NAME: flow

Farmer John always wants his cows to have enough water and thus has made a map of the N (1 <= N <= 700) water pipes on the farm that connect the well to the barn. He was surprised to find a wild mess of different size pipes connected in an apparently haphazard way. He wants to calculate the flow through the pipes.

Two pipes connected in a row allow water flow that is the minimum of the values of the two pipe's flow values. The example of a pipe with flow capacity 5 connecting to a pipe of flow capacity 3 can be reduced logically to a single pipe of flow capacity 3:

+---5---+---3---+ -> +---3---+ 

Similarly, pipes in parallel let through water that is the sum of their flow capacities:

   +---5---+ 
---+       +--- -> +---8---+ 
   +---3---+ 

Finally, a pipe that connects to nothing else can be removed; it contributes no flow to the final overall capacity:

   +---5---+ 
---+             -> +---3---+ 
   +---3---+-- 

All the pipes in the many mazes of plumbing can be reduced using these ideas into a single total flow capacity.

Given a map of the pipes, determine the flow capacity between the well (A) and the barn (Z).

Consider this example where node names are labeled with letters:

         +-----------6-----------+ 
A+---3---+B                      +Z 
         +---3---+---5---+---4---+ 
                C        D 

Pipe BC and CD can be combined:

         +-----------6-----------+ 
A+---3---+B                      +Z 
         +-----3-----+-----4-----+ 
                     D 

Then BD and DZ can be combined:

         +-----------6-----------+ 
A+---3---+B                      +Z 
         +-----------3-----------+ 

Then two legs of BZ can be combined:

         B 
A+---3---+---9---+Z 

Then AB and BZ can be combined to yield a net capacity of 3:

A+---3---+Z 

Write a program to read in a set of pipes described as two endpoints and then calculate the net flow capacity from 'A' to 'Z'. All networks in the test data can be reduced using the rules here.

Pipe i connects two different nodes a_i and b_i (a_i in range 'A-Za-z'; b_i in range 'A-Za-z') and has flow F_i (1 <= F_i <= 1,000). Note that lower- and upper-case node names are intended to be treated as different.

The system will provide extra test case feedback for your first 50 submissions.

INPUT FORMAT:

* Line 1: A single integer: N

* Lines 2..N + 1: Line i+1 describes pipe i with two letters and an integer, all space-separated: a_i, b_i, and F_i

The input contains multiple test cases.

SAMPLE INPUT:


A B 3 
B C 3 
C D 5 
D Z 4 
B Z 6 

OUTPUT FORMAT:

* Line 1: A single integer that the maximum flow from the well ('A') to the barn ('Z')

SAMPLE OUTPUT:

3

题目大意:同样是一道可耻的阅读理解,给你n个水管的连接方式和流量,'A'为水源,'Z'为牲口棚,问你水源到牲口棚的最大流量是多少?

分析:直接看样例发现是裸的最大流。字母的处理可以直接将就ASCII码来给节点编号(注意节点要留够),源点为'A'而汇点为'Z'。不存在任何难度就是一道模板题。

上代码:

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

const int MAXN = 210;
const int MAXM = 10000;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int from, to, next, cap;
};

Edge edge[MAXM];
int level[MAXN];
int head[MAXN];
int src, des, cnt;

void addedge( int from, int to, int cap )
{
	edge[cnt].from = from;
	edge[cnt].to = to;
	edge[cnt].cap = cap;
	edge[cnt].next = head[from];
	head[from] = cnt++;

	swap( from, to );

	edge[cnt].from = from;
	edge[cnt].to = to;
	edge[cnt].cap = 0;
	edge[cnt].next = head[from];
	head[from] = cnt++;
}

int bfs()
{
	memset( level, -1, sizeof level );
	cnt = 0;
	queue<int> q;
	while (!q.empty())
		q.pop();
	level[src] = 0;
	q.push( src );

	while (!q.empty())
	{
		int u = q.front();
		q.pop();

		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].to;
			if (edge[i].cap > 0 && level[v] == -1)
			{
				level[v] = level[u] + 1;
				q.push( v );
			}
		}
	}
	return level[des] != -1;
}

int dfs( int u, int f )
{
	if (u == des) return f;
	int tem;

	for (int i = head[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to;
		if (edge[i].cap > 0 && level[v] == level[u] + 1)
		{
			tem = dfs( v, min( f, edge[i].cap ) );
			if (tem > 0)
			{
				edge[i].cap -= tem;
				edge[i^1].cap += tem;
				return tem;
			}
		}
	}
	level[u] = -1;
	return 0;
}

int Dinic()
{
	int ans = 0, tem;
	while (bfs())
	{
		while ((tem = dfs( src, INF )) > 0)
		{
			ans += tem;
		}
	}
	return ans;
}

int main()
{
	int n;
	src = 'A', des = 'Z';
	while (cin >> n)
	{
		memset( head, -1, sizeof head );
		cnt = 0;
		char a, b;
		int c;
		for (int i = 1; i <= n; i++)
		{
			cin >> a >> b >> c;
			addedge( a, b, c );
			//把节点数留够,直接用字符的ASCII码作为编号
		}

		cout << Dinic() << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春哥111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值