【分层最短路】Magical Girl Haze

https://nanti.jisuanke.com/t/31001

有K次机会可以让一条边的权值变为0,求最短路。

在存储单源最短路的数组上多开一维状态,d[i][k]表示走到序号i的点,且让k条边权值为0时的最短路。

对于每个待更新的点,尝试不置零此边的状态和置零此边的状态,分别压入优先队列去更新其他状态。

另外,此题由于有重边,需要先去重,保留同起始点最短的边。

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int MAX_V = 100005;
const int MAX_E = 200005;
int N, M, K;
struct Dijkstra {
    struct Edge {
        int to, cost, next;
    } es[MAX_E];
    struct Node {
        int u, k;
        ll d;
        Node(int u, ll d, int k) : u(u), d(d), k(k) {}
        bool operator< (const Node& n) const {
            return d > n.d;
        }
    };
    int head[MAX_V];
    int V, E;
    ll d[MAX_V][15];
    bool vis[MAX_V][15];
    void init(int V) {
        this->V = V;
        this->E = 0;
        memset(head, -1, sizeof head);
    }
    void addEdge(int u, int v, int w) {
        es[E].to = v;
        es[E].cost = w;
        es[E].next = head[u];
        head[u] = E++;
    }
    void dijkstra(int s) {
        priority_queue <Node> Q;
        memset(d, 0x3f, sizeof d);
        memset(vis, 0, sizeof(vis));
        d[s][0] = 0;
        Q.push(Node(s, 0, 0));
        while (!Q.empty()) {
            int u = Q.top().u, k = Q.top().k;
            Q.pop();
            if (vis[u][k])
                continue;
            vis[u][k] = true;
            for (int i = head[u]; i != -1; i = es[i].next) {
                int v = es[i].to, w = es[i].cost;
                if (d[v][k] > d[u][k] + w) {
                    d[v][k] = d[u][k] + w;
                    Q.push(Node(v, d[v][k], k));
                }
                if (k + 1 <= K) {
                    if (d[v][k + 1] > d[u][k]) {
                        d[v][k + 1] = d[u][k];
                        Q.push(Node(v, d[v][k + 1], k + 1));
                    }
                }
            }
        }
    }
} dijk;
struct Elem {
    int u, v, w;
    bool operator< (const Elem& e) const {
        if (u == e.u && v == e.v) {
            return w < e.w;
        }
        if (u == e.u) {
            return v < e.v;
        }
        return u < e.u;
    }
} e[MAX_E];
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d", &N, &M, &K);
        dijk.init(N);
        for (int i = 0; i < M; i++) {
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
        }
        sort(e, e + M);
        int preu = 0, prev = 0;
        for (int i = 0; i < M; i++) {
            if (preu != e[i].u || prev != e[i].v) {
                dijk.addEdge(e[i].u, e[i].v, e[i].w);
                preu = e[i].u, prev = e[i].v;
            }
        }
        dijk.dijkstra(1);
        ll ans = INF;
        for (int i = 0; i <= K; i++) {
            ans = min(ans, dijk.d[N][i]);
        }
        printf("%lld\n", ans);
    }
}

原文地址:https://www.cnblogs.com/stolf/p/9572053.html

时间: 2024-10-11 10:31:40

【分层最短路】Magical Girl Haze的相关文章

2018icpc南京网络赛-L Magical Girl Haze (分层图最短路)

题意: 有向图,可以把k条路的长度变为0,求1到n的最短路 思路: 将图复制k份,一共k+1层图,对于每一条i→j,都连一条低层的i→高层的j,并且权值为0 即对每一对<i,j,w>,都加边<i,j,w>,<i+n,j+n,w>,<i+2n,j+2n,w>,....,<i+kn,j+kn,w> 同时加“楼梯”<i,j+n,0>,<i+n,j+2n,0>,...,<i+(k-1)n, j+kn> 然后跑一个1~(

ACM-ICPC 2018 南京赛区网络预赛 L. Magical Girl Haze(分层dijkstra)

题意:有n个地方,m条带权值的路,你有k次机会将一条路的权值变为0,求1到n的最短距离. 分析:这是一题分层dijkstra的模板题,因为k的大小不是很大,最坏的情况也就是10,而我们一般的最短路问题只是建一个平面的图. 而分层dijkstra是一个空间的.怎么操作呢? 举个简单的栗子 当数据如下是 n  m  k 3  2  1 1  2  5(路的起点1,终点2,权值5) 2  3  6 没有k的情况就是这样的 如果有k的情况,即1到2权值可能为0,2到3也可能为0,我们可以加一个平面表示他

ICPC 2018 南京网络赛 J Magical Girl Haze(多层图最短路)

传送门:https://nanti.jisuanke.com/t/A1958 题意:n个点m条边的路,你有k次机会将某条路上的边权变为0,问你最短路径长度 题解:最短路变形,我们需要在常规的最短路上多开 一维,记录,我消耗j次机会时的最短路径长度为多少 代码: /** * ┏┓ ┏┓ * ┏┛┗━━━━━━━┛┗━━━┓ * ┃ ┃ * ┃ ━ ┃ * ┃ > < ┃ * ┃ ┃ * ┃... ⌒ ... ┃ * ┃ ┃ * ┗━┓ ┏━┛ * ┃ ┃ Code is far away fro

计蒜客 31001 - Magical Girl Haze - [最短路][2018ICPC南京网络预赛L题]

题目链接:https://nanti.jisuanke.com/t/31001 题意: 一带权有向图,有 n 个节点编号1~n,m条有向边,现在一人从节点 1 出发,他有最多 k 次机会施展魔法使得某一条边的权变成 0,问他走到节点 n 的最小权值为多少. 题解: 将dist数组和vis数组都扩展一维: dist[c][i]代表:已经使用了 c 次变0魔法后,走到节点 i 的最短距离: vis[c][i]代表:已经使用了 c 次变0魔法后,走到节点 i 的最短距离,这个最短距离是否已经被准确计算

HDU5669 Road 分层最短路+线段树建图

分析:(官方题解) 首先考虑暴力,显然可以直接每次O(n^2) ?的连边,最后跑一次分层图最短路就行了. 然后我们考虑优化一下这个连边的过程 ,因为都是区间上的操作,所以能够很明显的想到利用线段树来维护整个图, 连边时候找到对应区间,把线段树的节点之间连边.这样可以大大缩减边的规模,然后再跑分层图最短路就可以了. 但是这样建图,每一次加边都要在O(logn)个线段树节点上加边,虽然跑的非常快,但是复杂度仍然是不科学的. 为了解决边的规模的问题,开两棵线段树,连边时候可以新建一个中间节点,在对应区

分层最短路-2018南京网赛L

大概题意: 题意:N个点,M条带权有向边,求将K条边权值变为0的情况下,从点1到点N的最短路. 拓展:可以改变K条边的权值为x 做法:把每个点拆成k个点,分别表示还能使用多少次机会,构造新图. 实际写的时候,不用真的拆点,用dist[i][j]表示从源点出发到点i,免费j条边的最小花费,在dijkstra中维护分层即可,每个节点要存价值,编号,已经用的免费条数. 1 #include <iostream> 2 #include <queue> 3 #include <cstd

[ACM]Magical Girl Haze

一.题面 样例输入: 15 6 11 2 21 3 42 4 33 4 13 5 64 5 2 样例输出: 3 来源:ACM-ICPC 2018 南京赛区网络预赛 二.思路 关键词:分层BFS. 考试时觉得题干意思很清晰--求可将k条边赋值为0的最短路.起初几个思路正确性均存疑,后来觉得应该要DP于是决定滞后了... 正解--分层BFS,个人认为思路与DP有些许相像,同时记录节点及当前已赋值为0的边数,则在跑最短路时(这里用的SPFA),可选择是否将该条边赋值为0,当且仅当已选边<k. 三.代码

ACM-ICPC 2018 南京赛区网络预赛 L. Magical Girl Haze

262144K There are NN cities in the country, and MM directional roads from uu to v(1\le u, v\le n)v(1≤u,v≤n). Every road has a distance c_ici?. Haze is a Magical Girl that lives in City 11, she can choose no more than KK roads and make their distances

Magical Girl Haze 南京网络赛2018

题意: 就是使不大于k条路的权值变为零后求最短路 解析: d[i][j]表示使j条路变为权值后从起点到点i的最短路径 这题不能用spfa做  tle #include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <cctype> #include <set> #include <v