蓝桥杯真题 - 魔法阵 - 题解

题目链接:https://www.lanqiao.cn/problems/3542/learning/

个人评价:难度 3 星(满星:5)

前置知识:迪杰斯特拉


整体思路

  • 这类题目的套路解法是把每一种状态都定义为图上的一个点,用迪杰斯特拉计算初始状态到每一点的最短距离,通过状态之间的合法转移来计算状态状态之间的距离;
  • 每一种状态由"节点编号"与"已选择免伤害边数"决定,定义 d i s p o s k disposk disposk 表示从状态 d i s 0 0 dis00 dis00 转移到节点 p o s pos pos,已选择 k k k 条免伤害边,则状态之间的距离有如下计算方式:

d i s p o s k = { min ⁡ ( d i s p r e i 0 + w p r e i − p o s ) k = 0 o r k = K min ⁡ ( d i s p r e i k − 1 ) o t h e r s disposk= \begin{cases} \min(dispre_i0+w_{pre_i-pos}) & k=0~or~k=K\\ \min(dispre_ik-1) & others \end{cases} disposk={min(disprei0+wprei−pos)min(dispreik−1)k=0 or k=Kothers

  • 其中 p r e i pre_i prei 表示节点 p o s pos pos 在迪杰斯特拉过程中的第 i i i 个前置节点编号; w p r e i − p o s w_{pre_i-pos} wprei−pos 表示从节点 p r e i pre_i prei 到节点 p o s pos pos 的距离 w w w 的值;
  • 当 k = 0 k=0 k=0 时的递推,即完全不使用魔法,最一般的迪杰斯特拉写法;
  • 当 k < K k<K k<K 时的递推,表示到当前节点连续选择 k k k 条边的最短距离等于从前置节点往前连续选择 k − 1 k-1 k−1 条边的距离;
  • 当 k = K k=K k=K 时的递推,表示之前某个时刻已经选好连续的 K K K 条边了,后续无法再选择新的边,此时用一般的迪杰斯特拉递推写法即可;
  • 由于从起点到终点可能不到 K K K 条边,或者不使用魔法的距离更短,所以最终答案为 min ⁡ ( d i s N − 1 K , d i s N − 1 0 ) \min(disN-1K,disN-10) min(disN−1K,disN−10)。

过题代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int maxn = 1000 + 100;
struct Node {
    int pos, k, dis;
    Node() {}
    Node(int pos, int k, int dis) : pos(pos), k(k), dis(dis) {}
};

bool operator<(const Node &a, const Node &b) {
    return a.dis > b.dis;
}

int n, k, m, u, v, w;
vector<Node> G[maxn];
priority_queue<Node> que;
int dis[maxn][100];
bool vis[maxn][100];

int main() {
#ifdef ExRoc
    freopen("test.txt", "r", stdin);
#endif // ExRoc
    ios::sync_with_stdio(false);

    cin >> n >> k >> m;
    for (int i = 0; i < m; ++i) {
        cin >> u >> v >> w;
        G[u].push_back(Node(v, 0, w));
        G[v].push_back(Node(u, 0, w));
    }
    memset(dis, 0x3f, sizeof(dis));
    que.push(Node(0, 0, 0));
    dis[0][0] = 0;
    while (!que.empty()) {
        Node tmp = que.top();
        que.pop();
        if (vis[tmp.pos][tmp.k]) {
            continue;
        }
        vis[tmp.pos][tmp.k] = true;
        for (Node &node: G[tmp.pos]) {
            // k == 0 表示不使用魔法,k == K 表示已使用过魔法
            if (tmp.k == 0 || tmp.k == k) {
                if (dis[node.pos][tmp.k] > dis[tmp.pos][tmp.k] + node.dis) {
                    dis[node.pos][tmp.k] = dis[tmp.pos][tmp.k] + node.dis;
                    que.push(Node(node.pos, tmp.k, dis[node.pos][tmp.k]));
                }
            }
            // 当 k < K 时,不能不使用魔法,所以只能直接取等号
            if (tmp.k < k) {
                if (dis[node.pos][tmp.k + 1] > dis[tmp.pos][tmp.k]) {
                    dis[node.pos][tmp.k + 1] = dis[tmp.pos][tmp.k];
                    que.push(Node(node.pos, tmp.k + 1, dis[node.pos][tmp.k + 1]));
                }
            }
        }
    }
    cout << min(dis[n - 1][0], dis[n - 1][k]) << endl;

    return 0;
}
相关推荐
无忧.芙桃14 分钟前
C++内存管理
c语言·开发语言·c++·青少年编程
金金计较.20 分钟前
Go语言-2
开发语言·算法·golang
郝学胜_神的一滴29 分钟前
C++11 工程级应用 11:编译期黑魔法,告别重复烂代码
c++·visual studio
计算机编程-吉哥31 分钟前
基于机器学习的城市交通拥堵分析与预测平台【计算机毕业设计选题·机器学习·随机森林算法】
hadoop·算法·随机森林·机器学习·课程设计·计算机毕业设计选题·大数据毕业设计选题推荐
zyeyeye1 小时前
C++入门:从HelloWorld到命名空间揭秘
c语言·开发语言·c++·算法
牧羊人.3331 小时前
动手学深度学习 04 | Dataset 和 DataLoader、数据增强
人工智能·pytorch·深度学习·算法
励志不掉头发的内向程序员1 小时前
【LibreCAD 2D架构】从 addHistory 到 RS_UndoCycle:LibreCAD 里的两套 History 与撤销机制
开发语言·c++·qt·学习·系统架构
elseif1231 小时前
【双指针/二分】P1102 A-B 数对
c++·算法·二分·双指针
电梯界知识分子1 小时前
江西抚州临川九尊府五层别墅:受限楼梯间里,全黑铝合金观光井道配曳引龙门架的落地记录
大数据·前端·网络·算法·家用电梯
雪落漂泊1 小时前
C++智能指针
开发语言·jvm·c++