欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PTA刷题Advanced甲级——1003.Emergency——Day(2)

程序员文章站 2022-06-07 10:46:07
...

题目描述

PTA刷题Advanced甲级——1003.Emergency——Day(2)简单翻译一下题目:
给出N个城市,M条无向边,每个城市都有一定数目的救援小组,所有边的边权已知。现在给出起点和终点,求从起点到终点的最短路径条数及最短路径上的救援小组数目之和。如果有多条最短路径,则输出数目之和最大的。

题目分析

由于我们的起点是固定的,所以本题就是求解出从起点到终点的最短距离,很明显这是一个单源最短路径问题,即Dijkstra算法。
但是由于每一个顶点都具有一个权重,对应于题中所说的每个城市有一定数量的搜救队员。我们需要找到一条最短路径且可以搜集到最多搜救队员的路径,即这条路径上经过的点权重和最大。
标准的Dijsktra算法解题,但是我们需要开辟两个数组分别记录点权和到达某点的最大点权和。接下来就是本题中最容易忽视的点,题目要求我们找出最短路径条数而不是最短路径长度。
PTA刷题Advanced甲级——1003.Emergency——Day(2)
我们可以看到从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√

相关标签: PTA甲级