PTA刷题Advanced甲级——1003.Emergency——Day(2)
程序员文章站
2022-06-07 10:46:07
...
题目描述
简单翻译一下题目:
给出N个城市,M条无向边,每个城市都有一定数目的救援小组,所有边的边权已知。现在给出起点和终点,求从起点到终点的最短路径条数及最短路径上的救援小组数目之和。如果有多条最短路径,则输出数目之和最大的。
题目分析
由于我们的起点是固定的,所以本题就是求解出从起点到终点的最短距离,很明显这是一个单源最短路径问题,即Dijkstra算法。
但是由于每一个顶点都具有一个权重,对应于题中所说的每个城市有一定数量的搜救队员。我们需要找到一条最短路径且可以搜集到最多搜救队员的路径,即这条路径上经过的点权重和最大。
标准的Dijsktra算法解题,但是我们需要开辟两个数组分别记录点权和到达某点的最大点权和。接下来就是本题中最容易忽视的点,题目要求我们找出最短路径条数而不是最短路径长度。
我们可以看到从V0到V2,可以有两条最短路径:1.V0->V2 2.V0->V1->V2
这两条最短路径长度都是2,样例中的答案也给出的是2,所以这会让大家产生混淆,以为题目要求我们输出的是最短路径长度。
因此,我们也需要单独开辟一个数组来记录最短路径条数,怎么更新这个数组中的值呢?
我们假设起点为s,终点为v,中介点为u,如果从s直接到达v的距离 > 从s到u再到v的距离和的话,我们就将最小距离更新,并且用num[u]来更新num[v],这条最短路径的条数应该是和从s到u的最短路径条数的相同的。
如果从s直接到达v的距离 = 从s到u再到v的距离和的话,我们就应该将num[v]+=num[u],此时又遇到了相同最短路径,条数应该+num[u]。
最终我们输出num[终点]和w[终点] (w是点权数组)。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX = 510;//最多结点数
const int INF = 100000000;
int st,ed,n,m;//起点,终点,点数,边数
int G[MAX][MAX];//邻接矩阵
int num[MAX];//num[i]记录到达i点的最短路径条数
int weight[MAX],w[MAX],d[MAX];//点权,w[i]表示到达点i时的最大点权,d[i]表示从起点到点i的最短距离
bool vis[MAX] = {false};//记录某个结点是否被访问过,初始都未访问过
void Dijkstra(int s)//s为起点
{
memset(num,0,sizeof(num));
memset(w,0,sizeof(w));
fill(d,d+MAX,INF);
num[s] = 1;
d[s] = 0;
w[s] = weight[s];
for(int j = 0;j < n;j++)
{
int u = -1;//记录当前距离最近的结点序号
int min = INF;
for(int i = 0;i < n;i++)
{
if(vis[i]==false && d[i] < min)
{
u = i;
min = d[i];
}
}
if(u == -1)
return;
vis[u] = true;
for(int k = 0;k < n;k++)
{
//如果k未被访问且u可以到达k且以u为中介点可以使d[k]更优
if(G[u][k]!=INF&&vis[k]==false)
{
if(d[u]+G[u][k]<d[k])
{
d[k] = d[u]+G[u][k];
w[k] = w[u]+weight[k];
num[k] = num[u];
}
else if(G[u][k]+d[u]==d[k])
{
if(weight[k]+w[u] > w[k])//以u为中介点可以形成更大的点权
w[k] = weight[k]+w[u];
num[k] += num[u];//此时遇到了一条最短长度相等的路径,要在原有基础上加上num[u]
}
}
}
}
}
int main()
{
scanf("%d %d %d %d",&n,&m,&st,&ed);//输入边数,点数,起点和终点
for(int i = 0;i < n;i++)
{
scanf("%d",&weight[i]);
}
int u,v;//两个相连的顶点
fill(G[0],G[0]+MAX*MAX,INF);//初始化图G
for(int i = 0;i < m;i++)
{
scanf("%d %d",&u,&v);
scanf("%d",&G[u][v]);
G[v][u] = G[u][v];
}
Dijkstra(st);
printf("%d %d\n",num[ed],w[ed]);//最短距离条数,最短路径中的最大点权
return 0;
}
答题用时19min
Q3——finish√