L2-001 紧急救援

参考网络上代码,加上一些理解注释,主要算法为Dijkstra

Dijkstra的三个基本数组visit[] disc[] path[]

在加上新需求记录“最短路径条数”和“救援队伍数目”


#include <iostream>
#include <string>
#include <cstdio>
#include <iomanip>
#include <vector>
#include <algorithm>

using namespace std;

#define INF 1000    // 题目已知最大不超过500

int main()
{
    int N, M, S, D;
    cin >> N >> M >> S >> D;
    int Team[N]; // 保存每个城市的救援队伍数目
    for (int i = 0; i < N; ++i)
    {
        cin >> Team[i];
    }
    int map_in[N][N]; // 城市间地图数据
    for (int i = 0; i < N; ++i)
    {
        for (int j = 0; j < N; ++j) // 默认初始化为最大值
            map_in[i][j] = INF;
    }
    // 接收输入城市间路径(图)
    for (int i = 0; i < M; ++i)
    {
        int pos_r, pos_c, cost;
        cin >> pos_r >> pos_c >> cost;
        map_in[pos_r][pos_c] = map_in[pos_c][pos_r] = cost;
    }
    // 下面执行Dijkstra最短路径算法(当最短路径出现多条时,比较救援队伍,从而决定下一个节点)
    bool visit[N]; // 标记城市是否已访问过
    int path[N]; // 记录路径
    int disc[N]; // 记录城市最短距离

    int teamnum[N]; // 记录队伍数目
    int pathnum[N]; // 记录最短路径数目(有可能多条最短路径)

    // 初始化
    for (int i = 0; i < N; ++i)
    {
        visit[i] = false;
        pathnum[i] = 0;
        disc[i] = 0;
        teamnum[i] = 0;
        path[i] = 0;
    }
    visit[S] = true;
    pathnum[S] = 1;
    disc[S] = 0;
    teamnum[S] = Team[S];
    // 先处理与起始点相连接的顶点城市
    for (int i = 0; i < N; ++i)
    {
        disc[i] = map_in[S][i];
        if (map_in[S][i] != INF && i != S)
        {
            path[i] = S;
            teamnum[i] = Team[i] + Team[S];
            pathnum[i] = 1; // 此时最短路径认为只有一条
        }
    }
    // 对剩余N-1个城市进行处理
    for (int i = 1; i < N; ++i)
    {
        int min_dis = INF;
        int u = S;
        // 找出最短距离
        for (int j = 0; j < N; ++j)
        {
            if (visit[j] == false && disc[j] < min_dis)
            {
                min_dis = disc[j];
                u = j;
            }
        }
        // 找出中间节点
        visit[u] = true;
        // 根据中间节点更新disc数组(最短距离)
        for (int j = 0; j < N; ++j)
        {
            if (false == visit[j]) // 未纳入最短路径
            {
                if (disc[j] > min_dis + map_in[u][j]) // 加入中间节点后,路径缩短,则更新
                {
                    disc[j] = min_dis + map_in[u][j]; // 更新距离
                    path[j] = u;    // 更新路径
                    pathnum[j] = pathnum[u]; // 更新最短路径数目(最短路径未增加)
                    teamnum[j] = teamnum[u] + Team[j]; // 更新救援队伍(此处小心)
                } else if (disc[j] == min_dis + map_in[u][j]) // 此时出现了另一条最短路径
                {
                    pathnum[j] = pathnum[j] + pathnum[u]; // 最短路径条数相加
                    // 最短路径相同,再比较救援队伍数目
                    if (teamnum[j] < teamnum[u] + Team[j]) // 选择救援队伍多的一条
                    {
                        teamnum[j] = teamnum[u] + Team[j];
                        path[j] = u;
                    }
                }
            }
        }
    }
    // 已处理完起始点S到其他任意节点的最短路径且最大救援队伍数目
    // 此时path[]中记录着起始点S到其余各节点的最短路径
    int pos(0);
    int out_path[N];
    int cur = D; // 从目的地查找到起始点S的路径
    while(cur != S)
    {
        out_path[pos++] = cur; // 记录从D->S的路径
        cur = path[cur]; // 找路径上的父节点
    }
    out_path[pos] = S; // 最后一个为起始点
    cout << pathnum[D] << " " << teamnum[D] << endl;
    for (int i = pos; i > 0; --i)
    {
        cout << out_path[i] << " ";
    }
    cout << out_path[0] << endl;

    return 0;

}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值