浏览器标题切换
浏览器标题切换end

PTA1003 - Emergency - Dijkstra的变形

题意

第一行给出四个数,分别代表城市数量(0 ~ n-1)、道路数量m、起点s、终点t。

第二行给出n个数,代表第i个城市救援队的数量

接下去给出m行,每行给出三个数x、y、z,表示x->y 距离z,是双向路。

最后让我们输出s->t的最短路条数 和 能聚集到的救援队的最大数量。

思路

本题是一个Dijkstra的变形,变形的部分就是下面的关键部分代码。

我们开两个数组保存结果,分别是ans1和ans2,

ans1:起点s到每个点最短路的数量 ans2:起点s到每个点(在距离最短的情况下)最多救援几支队伍。

但是要非常非常非常注意的一点就是:book数组标记的时候,book[s]=0而不是等于1,因为如果题目给出来的起点s和终点t恰好是同一个点,那么也是存在一条路线的。这个会造成样例答案都不对。

关键部分代码:

    if(!book[j])
    {
        if(dis[k]+e[k][j]<dis[j]) // 找到一条更短的路
        {
            dis[j]=dis[k]+e[k][j];
            ans1[j]=ans1[k]; // 更新ans1:起点s到每个点最短路的数量
            ans2[j]=ans2[k]+num[j];
        }
        else if(dis[k]+e[k][j]==dis[j]) // 如果最短路路径相等
        {
            ans1[j]=ans1[j]+ans1[k];
            if(ans2[k]+num[j]>ans2[j])
                ans2[j]=ans2[k]+num[j];
        }
    }

AC代码

#include<iostream>
#include<string>
#include<algorithm>
#include<stdio.h>

using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f

//5 6 0 2 城市数量0~n-1 路数量m s t
//1 2 1 5 3 n个数 第i个城市救援队的数量
//m行 x->y 距离z 双向路
//0 1 1
//0 2 2
//0 3 1
//1 2 1
//2 4 1
//3 4 1
//output:
//s->t的最短路条数 能聚集到的救援队的最大数量

const int N=550;
int e[N][N],dis[N],num[N],n,m,s,t,ans1[N],ans2[N];
//ans1:起点s到每个点最短路的数量   ans2:起点s到每个点(在距离最短的情况下)最多救援几支队伍
bool book[N];

void dijkstra()
{
    ans1[s]=1,ans2[s]=num[s]; // 最短路肯定有起码有一条,救援队数量起码有本身的数量(理解有问题)
    for(int i=0;i<n;i++)
        dis[i]=e[s][i]; // dis[i]=inf;
    //book[s]=1; 重要易错点 起点不能标记,因为起点自身到自身也是一条路径
    dis[s]=0;
    for(int i=0;i<n;i++)
    {
        int mi=inf,k;
        for(int j=0;j<n;j++)
        {
            if(!book[j]&&dis[j]<mi)
                k=j,mi=dis[j];//book[j]=1;
        }
        book[k]=1;
        for(int j=0;j<n;j++)
        {
            if(!book[j])
            {
                if(dis[k]+e[k][j]<dis[j]) // 找到一条更短的路
                {
                    dis[j]=dis[k]+e[k][j];
                    ans1[j]=ans1[k]; // 更新ans1:起点s到每个点最短路的数量
                    ans2[j]=ans2[k]+num[j];
                }
                else if(dis[k]+e[k][j]==dis[j]) // 如果最短路路径相等
                {
                    ans1[j]=ans1[j]+ans1[k];
                    if(ans2[k]+num[j]>ans2[j])
                        ans2[j]=ans2[k]+num[j];
                }
            }
        }
    }
}

int main()
{
    cin>>n>>m>>s>>t;
    for(int i=0;i<n;i++)
        cin>>num[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j)
                e[i][j]=0;
            else
                e[i][j]=inf;
        }
    }
    for(int i=0;i<m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        if(z<e[x][y]||z<e[y][x])
            e[x][y]=e[y][x]=z;
    }
    dijkstra();
    cout<<ans1[t]<<" "<<ans2[t];
    return 0;
};
posted @ 2021-02-25 19:16  抓水母的派大星  阅读(94)  评论(0编辑  收藏  举报