【PAT】甲级A1003

在这里插入图片描述
【解题思路】
Dijkstra算法的基础上要统计相同最短路径的条数,并且如果有多条相同边权的最短路径,输出具有最大点权的数目。

【解题过程】
首先,先回顾Dijkstra算法:
1.对于有权图,先确定起点start,创建一个数组dist[顶点个数],先把dist[start]设为0,其余各点为无穷大。
2.找出dist中最小的蓝点x,即离起点最近的点,把该点变白,即访问过该点(vist[x] = 1)。
3.遍历x的所有邻边y,如果起点经由x点到达y点所经历的路径更短,将dist
[y]值改为dist[x]+G[x][y]。
4.重复2,3两步,直到所有点都变白。这一步也就是算法要循环n次的原因。
代码如下:

//Dijkstra模版
void Dijkstra(int s){       //s为起点
    fill(d, d+MAXV, INF);   //fill函数将整个d数组赋为INF
    d[s] = 0;
    for(int i=0; i<n; i++){ //循环n次
        int u = -1;  MIN = INF; //u使d[u]最小,MIN存放该最小的d[u]
        for(int j=0;j<n;j++){   //找到未访问的顶点中d[]最小的
            u = j;
            MIN = d[j];
        }
        //找不到小于INF的d[u], 说明剩下的顶点和起点不连通
        if(u == -1) return;
        vis[u] = true;  //标记u已访问
        for(int v=0;v<n;v++){
            //如果v未访问 并且 u能达到v 并且 以u为中介点可以使d[v]更优
            if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){
                d[v] = d[u] + G[u][v];  //更新d[v]
            }
        }
    }
}

接着,这道题需要在模版基础上进行修改。题目要求找到如果最短路径有多条就要求给出最短路径的条数,并从找出具有最大点权的一条,输出最大点权。所以需要在原有代码的基础上创建两个数组:num[]和w[]。num用于记录每点到达起点的最短路径数目,w用于记录每点到达起点最短路径的最大点权值为多少。
在遍历x的所有邻接边的时候,如果经由x点到v点,距离更短,那num[v]=num[x](即到达v的路径条数和x的路径条数一致);如果经由x点到达v点的距离和v到原地距离一样,那么num[v]的值需要再加上num[x]。这一层还需要做一个判断,如果经由x到达v点的路径的点权之和大于原来v点的点权值,那么更新w[v]的值。

值得注意的是,当选择codeblock时,我在main函数里创建G[510][510]出现了报错,大概是超出了阈值,所以要把这个二维数组放在全局变量之中。dev则不需要这样

【完整代码】

#include <cstdio>

//memset函数的头文件
#include <cstring>

//fill函数的头文件
#include <algorithm>
using namespace std;

const int MAXV = 510;
const int INF = 100000000;

int G[MAXV][MAXV];
int n, m, st, ed;   //n点数 m边数 st起点 ed终点
int weight[MAXV];   //点权
int num[MAXV], w[MAXV], d[MAXV];    //num最短路径条数 w最大点权之和 d最短距离
bool vis[MAXV];

void Dijkstra(int s){   //s为起点
    fill(d, d+MAXV, INF);
    fill(num, num+MAXV, 0);
    fill(w, w+MAXV, 0);


    //关于起点的初始化
    d[s] = 0;
    w[s] = weight[s];
    num[s] = 1;

    for(int i=0;i<n;i++){
        int u=-1, MIN = INF;//u使d[u]最小,MIN存放该最小的d[u]
        for(int j=0;j<n;j++){   //找到未访问的顶点中d[]最小的,即离start点最近的点
            if(vis[j] == false && d[j] < MIN){
                u = j;
                MIN = d[j];
            }
        }
        //找不到小于INF的d[u],说明剩下的顶点和起点s不连通
        if(u == -1) return; //函数体内return表示终结该函数
        vis[u] = true;  //标记u为已访问
        for(int v=0;v<n;v++){
            //如果v未访问 并且 u能达到v 并且 以u为中介可以使d[v]更小
            if(vis[v] == false && G[u][v] != INF){
                if(d[u] + G[u][v] < d[v]){
                    d[v] = d[u] + G[u][v];
                    w[v] = w[u] + weight[v];
                    num[v] = num[u];
                }else if(d[u] + G[u][v] == d[v]){   //找到一条相同长度的路径
                    if(w[u] + weight[v] > w[v]){    //以u为中介点时点权之和更大
                        w[v] = w[u] + weight[v];
                    }
                    //最短路径条数与点权无关,必须写在外面
                    num[v] += 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]+MAXV*MAXV, INF);    //初始化图G,这里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);       //Dijkstra算法

    printf("%d %d", num[ed], w[ed]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值