NOI 4.3 799: Heavy Transportation

题目来源:http://noi.openjudge.cn/ch0403/799/

799: Heavy Transportation

总时间限制3000ms   内存限制65536kB

描述

Background
Hugo Heavy is happy. After the breakdown of the Cargolifter project he can nowexpand business. But he needs a clever man who tells him whether there reallyis a way from the place his customer has build his giant steel crane to theplace where it is needed on which all streets can carry the weight.
Fortunately he already has a plan of the city with all streets and bridges andall the allowed weights.Unfortunately he has no idea how to find the themaximum weight capacity in order to tell his customer how heavy the crane maybecome. But you surely know.

Problem
You are given the plan of the city, described by the streets (with weightlimits) between the crossings, which are numbered from 1 to n. Your task is tofind the maximum weight that can be transported from crossing 1 (Hugo's place)to crossing n (the customer's place). You may assume that there is at least onepath. All streets can be travelled in both directions.

输入

The first line contains the number of scenarios (city plans).For each city the number n of street crossings (1 <= n <= 1000) andnumber m of streets are given on the first line. The following m lines containtriples of integers specifying start and end crossing of the street and themaximum allowed weight, which is positive and not larger than 1000000. Therewill be at most one street between each pair of crossings.

输出

The output for every scenario begins with a line containing"Scenario #i:", where i is the number of the scenario starting at 1.Then print a single line containing the maximum allowed weight that Hugo can transportto the customer. Terminate the output for the scenario with a blank line.

样例输入

1
3 3
1 2 3
1 3 4
2 3 5

样例输出

Scenario #1:
4

来源

TUD Programming Contest 2004, Darmstadt, Germany

 -----------------------------------------------------

思路

本题的题意是找到图中两点之间容量最大的道路的容量(不是最大流问题,因为只能走一条道路)。道路的容量定义为道路上各边容量的最小值。

最短路变形题。

回忆Dijkstra算法,Dijkstra算法是建立在定理:“最短路径的子路径也是最短路”之上的。基于该定理,如果维护一个数组表示当前循环中各个点到起始点的距离,则该数组中的最小值就是最小值对应的节点到起始点的最短路

对于本题,首先想到可以用BFS不断更新每个节点到起始点的最大容量,这里有一个问题就是循环到什么时候一个节点到起始点的容量才能被确定下来。注意到道路的容量小于等于道路上边的容量,道路加长、循环次数变多的过程是容量不断减小的过程。循环过程中如果一个节点到起始点的容量比其余所有点到起始点的容量都大,则该点到起始点的最大容量就可以确定下来,因为别的点的容量已经小了,即使再通过边连到这个节点,形成的道路的容量也不会增大。

可以看到,“循环过程中如果一个节点到起始点的容量比其余所有点到起始点的容量都大,则该点到起始点的最大容量就可以确定下来”的过程与Dijkstra算法中“如果维护一个数组表示当前循环中各个点到起始点的距离,则该数组中的最小值就是最小值对应的节点到起始点的最短路”是一模一样的,因此该题可以套用Dijkstra算法的模板,只需修改求最值(最小->最大)和更新d数组的代码。

Dijkstra算法模板见博文HDU 2544 最短路(Dijkstra模板)

-----------------------------------------------------

代码 

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

const int NMAX = 1005;
int mat[NMAX][NMAX] = {};
int d[NMAX] = {};
bool vis[NMAX] = {};

int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("0403_799.txt");
	int t,cnt,n,m,s1,s2,w,i,j,maxid,maxv,dj;
	fin >> t;
	for (cnt=1; cnt<=t; cnt++)
	{
		memset(mat, 0, sizeof(mat));
		memset(d, 0, sizeof(d));
		memset(vis, 0, sizeof(vis));
		fin >> n >> m;
		for (i=0; i<m; i++)
		{
			fin >> s1 >> s2 >> w;
			mat[--s1][--s2] = w;
			mat[s2][s1] = w;
		}
		for (i=1; i<n; i++)
		{
			d[i] = mat[0][i];
		}
		for (i=0; i<n-1; i++)						// 最多n-1轮循环
		{
			maxv = 0;
			for (j=1; j<n; j++)						// 求当前d数组中未被访问过的元素的最大值
			{
				if (d[j]>maxv && !vis[j])
				{
					maxv = d[j];
					maxid = j;
				}
			}
			vis[maxid] = 1;							// maxid被访问过了
			if (maxid == n-1)						// 如果终点被确定,输出结果,跳出循环
			{
				cout << "Scenario #" << cnt << ":" << endl;
				cout << maxv << endl << endl;
				break;
			}
			for (j=1; j<n; j++)						// 维护d数组
			{
				if (mat[maxid][j]>0 && !vis[j])
				{
					dj = d[j];
					d[j] = min(maxv, mat[maxid][j]);
					d[j] = max(dj, d[j]);
				}
			}
		}
	}
	fin.close();
#endif
#ifdef ONLINE_JUDGE
	int t,cnt,n,m,s1,s2,w,i,j,maxid,maxv,dj;
	cin >> t;
	for (cnt=1; cnt<=t; cnt++)
	{
		memset(mat, 0, sizeof(mat));
		memset(d, 0, sizeof(d));
		memset(vis, 0, sizeof(vis));
		cin >> n >> m;
		for (i=0; i<m; i++)
		{
			cin >> s1 >> s2 >> w;
			mat[--s1][--s2] = w;
			mat[s2][s1] = w;
		}
		for (i=1; i<n; i++)
		{
			d[i] = mat[0][i];
		}
		for (i=0; i<n-1; i++)						// 最多n-1轮循环
		{
			maxv = 0;
			for (j=1; j<n; j++)						// 求当前d数组中未被访问过的元素的最大值
			{
				if (d[j]>maxv && !vis[j])
				{
					maxv = d[j];
					maxid = j;
				}
			}
			vis[maxid] = 1;							// maxid被访问过了
			if (maxid == n-1)						// 如果终点被确定,输出结果,跳出循环
			{
				cout << "Scenario #" << cnt << ":" << endl;
				cout << maxv << endl << endl;
				break;
			}
			for (j=1; j<n; j++)						// 维护d数组
			{
				if (mat[maxid][j]>0 && !vis[j])
				{
					dj = d[j];
					d[j] = min(maxv, mat[maxid][j]);
					d[j] = max(dj, d[j]);
				}
			}
		}
	}
#endif
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80736457