PAT A1003 Emergency (25分)

原题

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C​1​​ and C​2​​ - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers
c​1​​ , c​2​​ and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1​​ to C​2​​ .

Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C​1​​ and C​2​​ , and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

大体翻译

就是要求求图的最短路径,并且当有多条最短路径时,比较最短路径的顶点权重和,记录权重大的权重和以及最短路径的个数

思路

该题求的是两个顶点间的最短路径,因此使用Dijkstra算法
在此基础上还要添加:当两个路径长度相等时,比较两条路径上顶点的权重和并修改
那么如何实现呢?

拿一个特殊的图作为例子:
红色的数字为顶点的权重,也就是每个城市的救援数
在这里插入图片描述
由此可见顶点0到顶点1的最短路径有3条,长度都为8,但是按照顶点权重和来说应该走顶点0->顶点3->顶点1这一条。
但是在遇到顶点3之前已经遇到顶点2了(Dijkstra思想),因此在遇到顶点3时,需要将0->3->1的权重和与0->2->1的权重和进行比较。
此时若只有顶点3的权重是无法比较的,还需要顶点3之前的权重和再加上顶点1的权重再与已经记录的0->2->1路线的权重和进行比较。
因此类似于记录最短路径长度的数组一样,我们也要设置一组数组记录到每个顶点的最大顶点权重和,这样当遇到两个最短路径相同时,比较3的权重和与2的权重和即可,若前者大于后者,则需要修改到2位置的最大顶点权重和。
如图所示:
蓝色数字即为到每个顶点的最大顶点权重和
可以看出,权重和是叠加的
在这里插入图片描述
此外还有最短路径的数目
无论权重和的比较结果如何,当遇到两个最短路径相同时,都需要修改最短路径的数目。
但是如上图显示一样,当遇到0->3->1时最短路径加1,遇到0->4->1时最短路径加1,但是当遇到1->6->7时再加1就不符合了
因此也需要设置一个数组,用来计算到达每个顶点时的最短路径数目
在这里插入图片描述
每个顶点的最短路径数目等于到达该顶点的所有顶点最短路径数目之和
所以当遇到两条相同最短路径时,需要将自身的最短路径数目加上新遇到的顶点的最短路径数目(因为自身的最短路径数目已经是之前遇到的顶点的最短路径数目之和了)
例如:在顶点1遇到顶点3时,它的最短路径数目就从1变成了2,在顶点1遇到顶点4时,它的最短路径数目又从2变成了3

上述的这两个模块只要合理地添加到Dijkstra算法中就可以了

还值得注意的是本题使用的数组较多,要求空间较大,可能会出现段出错的情况,因此可以把数组定义成全局变量

第一次编写

#include <iostream>
#include <queue>
using namespace std;
#define MaxVertexNum 501
typedef int VertexType;
typedef int EdgeType;
#define MAX 2000

typedef struct {
	VertexType Vex[MaxVertexNum];
	EdgeType Edge[MaxVertexNum][MaxVertexNum];
	int vexnum, arcnum;
}MGraph;

int s[MaxVertexNum], dist[MaxVertexNum];
int num[MaxVertexNum], weight[MaxVertexNum];

void Dijkstra(MGraph G, int v, int m)
{
	for (int i = 0; i < G.vexnum; i++)//初始化
	{
		dist[i] = G.Edge[v][i];
		s[i] = 0;
		if (i == v)
			weight[i] = G.Vex[v];
		else
			weight[i] = G.Vex[i] + G.Vex[v];
		num[i] = 1;
	}
	s[v] = 1;
	for (int i = 1; i < G.vexnum; i++)//还剩下n-1个顶点
	{
		int min = MAX;
		int u;
		for (int j = 0; j < G.vexnum; j++)//找到最短路径
		{
			if (s[j] == 0 && dist[j] < min)
			{
				min = dist[j];
				u = j;
			}
		}
		s[u] = 1;
		for (int j = 0; j < G.vexnum; j++)//找到最短路径后修改数组的部分
		{
			if (s[j] == 0 && dist[u] + G.Edge[u][j] < dist[j])
			{
				dist[j] = dist[u] + G.Edge[u][j];
				weight[j] = G.Vex[j] + weight[u];
				num[j] = num[u];
			}
			else if (s[j] == 0 && dist[u] + G.Edge[u][j] == dist[j])
			{
				num[j] += num[u];
				if (weight[j] < weight[u] + G.Vex[j])
					weight[j] = weight[u] + G.Vex[j];
			}
		}
	}
	cout << num[m] << " " << weight[m] << endl;
}

MGraph G;

int main()
{
	int vex, arc;
	cin >> vex >> arc;
	G.vexnum = vex;
	G.arcnum = arc;
	int bef, las;
	cin >> bef >> las;
	for (int i = 0; i < vex; i++)
	{
		cin >> G.Vex[i];
	}
	for (int i = 0; i < G.vexnum; i++)
	{
		for (int j = 0; j < G.vexnum; j++)
			G.Edge[i][j] = MAX;
	}
	int fir, sec, weight;
	for (int j = 0; j < arc; j++)
	{
		cin >> fir >> sec >> weight;
		G.Edge[fir][sec] = weight;
		G.Edge[sec][fir] = weight;
	}
	Dijkstra(G, bef, las);
	return 0;
}

运行结果

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值