PAT甲级1003

PAT甲级1003

题目简述

有n个城市(n<=500),城市之间有m条道路,起点城市s,终点城市d,第二行输入为每个城市中的救援队伍数量,以后m行就是起点城市到重点城市之间的路径长度L。我们需要的是求出起点城市到重点城市的最短路径数和在最短路径上的救援队伍数量

解题思想

首先可以看出这是一个明显的点对点最短路径搜索的题目,我们能想到的就是BFS和成熟的迪杰斯特拉算法(PS:我竟然还看到了DFS解法,我没想通这是为啥可以,附上链接:https://blog.csdn.net/qq_41764621/article/details/87269860)
对于BFS我们是需要做出结束条件的更改,我们并不是只要求出最短路径即可,我们还需要求出最短路径的数量,因此对比之下迪杰斯特拉算法较为适合这个题目
首先简述一下迪杰斯特拉算法:我们需要一个起点,然后依次遍历除了起点以外的所有顶点,更改他们之间的最短路径,例如:起点到w的距离>起点到midv的距离+midv到w的距离,会在最短距离中更改并且在path中更改他的点为midv,依次遍历完为止
接下来是题目中的更改,我们需要一个amount数组拿来存储可以来的救援队伍数量,需要一个mind数组拿来存储最短路径数量,并且在算法中加一个判断,用来更改amount数组和mind数组,判断条件就是当前路径长度等于最短路径长度时直接对两个数组做出更改

附上自己的代码(PS:自己写迪杰斯特拉调试起来还是有点困难,就直接拿了他们的代码阅读调试)

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
 
int t[501];//cityrescueteamnumber
int amount[501];//最短路径基础上能来的rescueteamnumber 
int mind[501];//表示起始点到其他各点最短路径的数目 
int cost[501][501];//各点之间的路径长度 
int ds[501];//各点之间的最短路径 
int ischecked[501];//是否被访问过 
int n,m,s,d;//n=city;m=road;s=begincity;d=endcity 
const int inf=(1<<30)-1;//相当于将1在二进制中左移30位然后-1 
 
void dij(){
    amount[s]=t[s];
    mind[s]=1;
    for(int i=0;i<n;i++){
        ds[i]=cost[s][i];
        ischecked[i]=false;
 
        if(ds[i]!=inf&&i!=s){
            mind[i]=1;
            amount[i]=t[i]+amount[s];
        }
    }
    ischecked[s]=true;
    for(int node=0;node<n;node++){
        int minV=-1;
        int minC=inf;
        //选最短距离最小的顶点
        for(int i=0;i<n;i++){
            if(!ischecked[i]&&ds[i]<minC){
                minC=ds[i];
                minV=i;
            }
        }
        if(minV==-1){
            continue;
        }
        //访问此顶点
        ischecked[minV]=true;
        for(int i=0;i<n;i++){
            //查看此顶点的所有未访问邻居
            if(!ischecked[i]&&cost[minV][i]<inf){
                //如果两种路径相等,则更新最短路径的数目,更新队伍的数目
                if(ds[i]==ds[minV]+cost[minV][i]){
                    mind[i]+=mind[minV];
                    amount[i]=max(amount[i],amount[minV]+t[i]);
                }
                //如果比原路径小,更新为最短路径,最短路径数目为1.
                else if(ds[i]>ds[minV]+cost[minV][i]){
                    ds[i]=ds[minV]+cost[minV][i];
                    mind[i]=mind[minV];
                    amount[i]=amount[minV]+t[i];
                }
            }
        }
    }
}
 
int main(void){
    scanf("%d %d %d %d",&n,&m,&s,&d);
    for(int i=0;i<n;i++){
        scanf("%d",&t[i]);
    }
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            cost[i][j]=cost[j][i]=inf;
        }
    }
    for(int i=0;i<m;i++){
        int c1,c2,c;
        scanf("%d %d %d",&c1,&c2,&c);
 
        if(c<cost[c1][c2]){
            cost[c1][c2]=cost[c2][c1]=c;
        }
    }
    dij();
    printf("%d %d",mind[d],amount[d]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值