原题
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, C1 and C2 - 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
c1 , c2 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 C1 to C2 .
Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2 , 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;
}