当前位置: 首页 > article >正文

机试题——到邻国目标城市的最短距离

题目描述

A国与B国是相邻的两个国家,每个国家都有很多城市。国家内部有很多连接城市的公路,国家之间也有很多跨国公路,连接两个国家的边界城市。两个国家一共有N个城市,编号从1到N,一共有M条公路,包括国内公路与跨国公路。小明生活在A国的城市1(即编号为1的城市),想去B国的城市N游玩,由于小明办理的是只能入境一次的签证,所以从城市1到城市N的路径中,只能通过一条跨国公路。每条公路都有一个距离,并且通过这条公路会有一个花费。请帮小明计算出从城市1到城市N的最短距离,在距离最短的前提下,再计算出最少花费。如果无法到达城市N,输出-1。

输入描述

  • 第一行是一个整数N,表示两个国家的城市数量
  • 第二行是一个整数M,表示两个国家的公路数量,包括国内公路与跨国公路
  • 第三行是一个长度为N的字符串,字符串第i个(从1开始计数)字符为A或B,表示城市i属于A国或B国,其中第1个字符一定为A,第N个字符一定为B
  • 接下来M行,每行包含4个整数U, V, W, C,表示编号为U的城市与编号为V的城市之间存在一条公路,长度是W,花费是C。每条公路是双向的。

输出描述

  • 输出城市1到城市N的最短距离,并在距离最短的前提下,再输出最少花费。如果无法到达城市N,输出-1。

用例输入

5 5 
AABBB 
3 1 200 1 
2 3 150 3 
5 2 160 5 
4 3 170 7 
4 5 170 9
540 17

可以找到一条最优线路:城市1(A国) → 城市3(B国) → 城市4(B国) → 城市5(B国)。而且只通过一条跨国公路:城市1 → 城市3。

  • 距离 = 200 + 170 + 170 = 540
  • 花费 = 1 + 7 + 9 = 17

解题思路

我们可以使用 BFS (广度优先搜索)来解决这个问题。BFS 是处理最短路径问题的有效方法,但因为该问题同时涉及到 最短距离最小花费,并且约束条件是最多只能使用一次跨国公路,因此我们需要对状态进行细致管理。

我们定义一个 状态结构体 (State) 来表示每个城市的状态,包括当前城市编号、当前总距离、当前总花费以及是否已经过跨国公路。为了保证同时考虑距离和花费,我们将每个城市分为两种状态:

  • flag = 0 表示还没有经过跨国公路。
  • flag = 1 表示已经经过一次跨国公路。

使用 队列 (queue) 来模拟 BFS,对于每条公路(国内或跨国),根据是否是跨国公路的条件进行更新:

  • 对于 国内公路,可以继续前进。
  • 对于 跨国公路,只能走一次,且必须确保不重复跨国。

最终,通过 BFS 搜索完成后,输出到达城市N的最短距离和最小花费。

优化点:使用优先队列

代码

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

struct Edge {
    int u, v, w, c;
};

struct State {
    int dist, cost, node, flag;
    bool operator>(const State& other) const {
        // 优先按距离排,再按花费排
        if (dist == other.dist) {
            return cost > other.cost;
        }
        return dist > other.dist;
    }
};

int main() {
    int n, m;
    cin >> n >> m;

    string countries;
    cin >> countries;

    vector<vector<Edge>> graph(n + 1);  // 图的邻接表

    // 读取公路信息
    for (int i = 0; i < m; i++) {
        int u, v, w, c;
        cin >> u >> v >> w >> c;
        graph[u].push_back({ u, v, w, c });
        graph[v].push_back({ v, u, w, c });
    }

    // 初始化距离和花费
    vector<int> dist(n + 1, INT_MAX);
    vector<int> cost(n + 1, INT_MAX);
    dist[1] = 0;
    cost[1] = 0;

    priority_queue<State, vector<State>, greater<State>> pq;
    pq.push({ 0, 0, 1, 0 });  // 从城市1开始,距离0,花费0,未跨国

    while (!pq.empty()) {
        State current = pq.top();
        pq.pop();

        int u = current.node;
        int current_dist = current.dist;
        int current_cost = current.cost;
        int current_flag = current.flag;

        if (current_dist > dist[u] || (current_dist == dist[u] && current_cost > cost[u])) {
            continue;  // 如果当前状态不是最优的,跳过
        }

        for (const Edge& edge : graph[u]) {
            int v = edge.v;
            int next_dist = current_dist + edge.w;
            int next_cost = current_cost + edge.c;

            bool isSameCountry = (countries[u - 1] == countries[v - 1]);

            if (isSameCountry) {
                // 国内公路,继续走
                if (next_dist < dist[v] || (next_dist == dist[v] && next_cost < cost[v])) {
                    dist[v] = next_dist;
                    cost[v] = next_cost;
                    pq.push({ next_dist, next_cost, v, current_flag });
                }
            }
            else {
                // 跨国公路,只能走一次
                if (current_flag == 0) {
                    if (next_dist < dist[v] || (next_dist == dist[v] && next_cost < cost[v])) {
                        dist[v] = next_dist;
                        cost[v] = next_cost;
                        pq.push({ next_dist, next_cost, v, 1 });
                    }
                }
            }
        }
    }

    // 输出结果
    if (dist[n] == INT_MAX) {
        cout << -1 << endl;  // 如果无法到达城市N
    }
    else {
        cout << dist[n] << " " << cost[n] << endl;  // 输出最短距离和最小花费
    }

    return 0;
}

http://www.kler.cn/a/531091.html

相关文章:

  • 八. Spring Boot2 整合连接 Redis(超详细剖析)
  • 【C++语言】卡码网语言基础课系列----5. A+B问题VIII
  • 【C语言入门】解锁核心关键字的终极奥秘与实战应用(二)
  • 基于人脸识别的课堂考勤系统
  • 基于python的Kimi AI 聊天应用
  • 基于WiFi的智能照明控制系统的设计与实现(论文+源码)
  • 基于单片机的智能感控杆设计(论文+源码)
  • 【电路笔记】-计数器与分频
  • Tree Compass( Codeforces Round 934 (Div. 2) )
  • 如何生成强密码:提高网络安全性的全面指南
  • 【C语言入门】解锁核心关键字的终极奥秘与实战应用(三)
  • win32汇编环境,窗口程序中使用进度条控件
  • 上海路网道路 水系铁路绿色住宅地工业用地面图层shp格式arcgis无偏移坐标2023年
  • HarmonyOS:给您的应用添加通知
  • 计算机网络 应用层 笔记 (电子邮件系统,SMTP,POP3,MIME,IMAP,万维网,HTTP,html)
  • 【Linux】--- 基础IO
  • 用deepseek R1把本地的AI工具都做成离线
  • !力扣 84. 柱状图中最大矩形
  • Java JWT 技术详解与实践指南
  • 【RocketMQ】RocketMq之IndexFile深入研究
  • 机器学习day5
  • 【PDF提取局部内容改名】批量获取PDF局部文字内容改名 基于QT和百度云api的完整实现方案
  • 后盾人JS -- 原型
  • C语言教学第四课:控制结构
  • 内核定时器3-用户空间定时器
  • Docker Hub 镜像 Pull 失败的解决方案