PAT甲级-1111 Online Map

题目

题目大意

给出城市个数n,边的数目m,接下来的m行以v1 v2 one-way length time的形式给出各节点的连通情况。如果one-way = 1,那么这条边是单向的,如果 = 0,则这条边是双向的。最后给出起点和终点。要求输出最短路径,如果有多条最短路径,选择时间花费最少的那条;要求输出时间最少路径,如果有多条时间最少路径,选择通过节点个数最少的路径。如果最短路径和时间最少路径完全一致,则输出一行;若不一致,输出两行。不仅要输出最短距离或最少时间,也要输出路径的每个节点。

思路

用两次迪杰斯特拉算法,一次计算最短路径,另一次计算时间最少的路径。然后输出路径用递归函数来回溯解决。需要注意的是,计算时间最少路径中,通过节点数最少的才是最佳路径,因此需要加一个nodenum数组来计算每个路径的节点数,如果不考虑这种情况,测试点4是过不了的。剩下的根据题意模拟就可以了。

代码

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

int n, m, start, des;
int g[510][510] = {0};  // 图
int Time[510][510] = {0};  // 时间矩阵,用time会与C++的time()起冲突
vector<int> dist;  // 最短路径的长度
vector<int> mintime;  // 最少时间的路径
vector<int> path;  // 记录每个最短路径节点的前驱节点
vector<int> tpath;  // 记录每个最少时间路径节点的前驱节点
vector<int> res;  // 记录最佳最短路径的节点
vector<int> tres;  // 记录最佳最少时间路径的节点
vector<int> nodenum;  // 记录路径经过的节点数量

void dijie(){
    bool visited[510] = {false};
    dist[start] = 0;
    mintime[start] = 0;
    for (int cnt = 0; cnt < n; cnt++){
        int now = -1, minl = INT_MAX;
        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];
                    mintime[i] = mintime[now] + Time[now][i];
                    path[i] = now;  // 记录前驱节点
                }else if (dist[i] == dist[now] + g[now][i]){
                    if (mintime[i] > mintime[now] + Time[now][i]){
                        mintime[i] = mintime[now] + Time[now][i];
                        path[i] = now;  // 记录前驱节点
                    }
                }
            }
        }
    }
}

void dijieTime(){
    bool visited[510] = {false};
    mintime[start] = 0;
    for (int cnt = 0; cnt < n; cnt++){
        int now = -1, mint = INT_MAX;
        for (int i = 0; i < n; i++){
            if (!visited[i] && mintime[i] < INT_MAX){
                if (mint > mintime[i]){
                    mint = mintime[i];
                    now = i;
                }
            }
        }

        if (now == -1){
            return;
        }
        visited[now] = true;

        for (int i = 0; i < n; i++){
            if (!visited[i] && Time[now][i] < INT_MAX){
                if (mintime[i] > mintime[now] + Time[now][i]){
                    mintime[i] = mintime[now] + Time[now][i];
                    tpath[i] = now;  // 记录前驱节点
                    nodenum[i] = nodenum[now] + 1;  // 更新节点个数
                }else if (mintime[i] == mintime[now] + Time[now][i]){
                    if (nodenum[i] > nodenum[now] + 1){
                        nodenum[i] = nodenum[now] + 1;
                        tpath[i] = now;
                    }  // 测试点4
                }
            }
        }
    }
}

void printPath(int node){
    if (node == start){
        res.push_back(start);
        return;
    }
    printPath(path[node]);
    res.push_back(node);
}  // 记录path

void printTpath(int node){
    if (node == start){
        tres.push_back(start);
        return;
    }
    printTpath(tpath[node]);
    tres.push_back(node);
}  // 记录tpath

int main(){
    cin >> n >> m;
    for (int i = 0; i < n; i++){
        for (int j = 0; j < n; j++){
            g[i][j] = (i == j) ? 0 : INT_MAX;
            Time[i][j] = (i == j) ? 0 : INT_MAX;
        }
    }  // 初始化图和时间矩阵
    for (int i = 0; i < m; i++){
        int v1, v2, way, length, t;
        cin >> v1 >> v2 >> way >> length >> t;
        if (way == 1){
            g[v1][v2] = length;
            Time[v1][v2] = t;
        }else{
            g[v1][v2] = g[v2][v1] = length;
            Time[v1][v2] = Time[v2][v1] = t;
        }
    }  // 构造图和时间矩阵
    cin >> start >> des;

    dist.resize(n, INT_MAX);
    path.resize(n, -1);
    tpath.resize(n, -1);
    mintime.resize(n, INT_MAX);
    nodenum.resize(n, 0);

    dijie();
    printPath(des);
    fill(mintime.begin(), mintime.end(), INT_MAX);
    dijieTime();
    printTpath(des);

    int flag = 1;  // 输出一行
    if ((int)res.size() != (int)tres.size()){
        flag = 0;  // 输出两行
    }else{
        for (int i = 0; i < (int)res.size(); i++){
            if (res[i] != tres[i]){
                flag = 0;
                break;
            }
        }
    }

    if (flag){
        cout << "Distance = " << dist[des] << "; Time = " << mintime[des] << ": ";
        for (int i = 0; i < (int)tres.size(); i++){
            cout << tres[i];
            if (i != (int)tres.size() - 1){
                cout << " -> ";
            }
        }
        cout << endl;
    }else{
        cout << "Distance = " << dist[des] << ": ";
        for (int i = 0; i < (int)res.size(); i++){
            cout << res[i];
            if (i != (int)res.size() - 1){
                cout << " -> ";
            }
        }
        cout << endl;
        cout << "Time = " << mintime[des] << ": ";
        for (int i = 0; i < (int)tres.size(); i++){
            cout << tres[i];
            if (i != (int)tres.size() - 1){
                cout << " -> ";
            }
        }
        cout << endl;
    }

    return 0;
}

猜你喜欢

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