PAT甲级-1087 All Rodes Lead to Rome

题目

题目大意

给出城市数量n和路的数目k,和起点名称。然后给出剩下n - 1个城市名称及其对应的happy值,以及边的连通情况。规定“ROM”为终点名称。如果最短路径有多条,那么happy值最大的路径为最佳路径。要求输出从起点到终点的最短路径的数目,最短路径的长度,最短路径中最佳路径的happy值,以及该路径的平均happy值。再输出该路径所通过的节点。

思路

毫无疑问,定源点求最短路径用迪杰斯特拉,求重复路径的数目可以加一个num数组,happy数组相当于之前写过题目中的cost数组,再用path数组记录最短路径中每个节点的前驱节点。题目中的节点名字是3个字母,可以用map来处理每个节点名字到下标的映射。

代码

#include <iostream>
#include <vector>
#include <map>
#include <climits>
using namespace std;

int n, k, start;
map<string, int> mp;  // 每个节点名字到索引的映射
map<int, string> mp2;  // 每个节点索引到名字的映射
vector<int> happy;  // happy值,起点值为0
int g[210][210] = {0};  // 图
vector<int> dist;  // 记录最短路径
vector<int> path;  // 记录最短路径中每个节点的前驱节点
vector<int> num;  // 到每个节点的重复路径的个数
vector<int> happiness;  // 到每个节点最短路径的happy累计值
vector<string> res;  // 存储最佳路径经过的节点名称

void dijie(){
    bool visited[210] = {false};
    dist[0] = 0;
    num[0] = 1;
    for (int cnt = 0; cnt < n; cnt++){
        int now = -1, minl = INT_MAX;  // now为要激活的节点
        for (int i = 0; i < n; i++){
            if (!visited[i] && dist[i] < INT_MAX){
                if (minl > dist[i]){
                    minl = dist[i];
                    now = i;
                }
            }
        }  // 找到要激活的节点

        if (now == -1){
            return;
        }  // 如果找不到,返回
        visited[now] = true;  // 激活节点

        for (int i = 0; i < n; i++){
            if (!visited[i] && g[now][i] < INT_MAX){
                if (dist[i] > dist[now] + g[now][i]){
                    dist[i] = dist[now] + g[now][i];
                    happiness[i] = happiness[now] + happy[i];
                    num[i] = num[now];  // 继承重复路径的个数
                    path[i] = now;  // 记录前驱节点
                }else if (dist[i] == dist[now] + g[now][i]){
                    num[i] += num[now];  // 累加重复路径的个数
                    if (happiness[i] < happiness[now] + happy[i]){
                        happiness[i] = happiness[now] + happy[i];
                        path[i] = now;  // 记录前驱节点
                    }
                }
            }
        }
    }
}

void printPath(int node){
    if (node == 0){
        res.push_back(mp2[0]);
        return;
    }  // 如果为起始节点,则回溯完毕,返回
    printPath(path[node]);
    res.push_back(mp2[node]);
}

int main(){
    cin >> n >> k;
    happy.resize(n, 0);
    int des;  // 终点的下标
    for (int i = 0; i < n; i++){
        string name;
        cin >> name;
        if (name == "ROM"){
            des = i;
        }
        mp[name] = i;
        mp2[i] = name;
        if (i != 0){
            cin >> happy[i];
        }
    }  // start为0
    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            g[i][j] = (i == j) ? 0 : INT_MAX;
        }
    }  // 初始化图
    for (int i = 0; i < k; i++){
        string c1, c2;
        int dis;
        cin >> c1 >> c2 >> dis;
        g[mp[c1]][mp[c2]] = g[mp[c2]][mp[c1]] = dis;
    }  // 构建图

    dist.resize(n, INT_MAX);
    num.resize(n, 0);
    path.resize(n, 0);
    happiness.resize(n, 0);
    dijie();

    printPath(des);
    int avgHappy = happiness[des] / ((int)res.size() - 1);
        cout << num[des] << " " << dist[des] << " " << happiness[des] << " " << avgHappy << endl;
    for (int i = 0; i < (int)res.size(); i++){
        cout << res[i];
        if (i != (int)res.size() - 1){
            cout << "->";
        }
    }
    cout << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_74092648/article/details/143211979