洛谷题单指南-最短路-P4568 [JLOI2011] 飞行路线

原题链接:https://www.luogu.com.cn/problem/P4568

题意解读:n个节点带权图中,从起点走到终点,最多有k条边长度可以清0,求最短路径长度是多少。

解题思路:

有k条边长度可以视为0,也就是从每一个点走到邻点总有一条长度为0的边,要确保走长度为0的边不超过k次,可以用到分层图的技巧。

所谓分层图,就是建立0~k一共k+1个图,每个图内部节点关系完全一样。

如此以来,图中节点编号x需要调整为第k层是x+n*k,可以确保不会重复。

对于输入给定的任意一条边u->v,在每一层图中建立双向连接,边长为给定权值;

同时还要将每一层的u与下一层的v相连,也要将每一层的v与下一层的u相连,边长为0。

这样从起点s到第k层的终点t+n*k的最短路径,就是正好走了k次0边后所能得到的最短路径长度。

需要注意,题目要求是不超过k次走长度为0的路径,因此允许在中间任意一层提前到达终点,只需要将相邻层的终点用一条长度为0的边相连即可。

完成建图之后,跑一遍Dijikstra算法就大功告成。

100分代码:

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;

const int N = 110005, M = 2200005;  

int h[N], e[M], w[M], ne[M], idx;
int dist[N];
bool vis[N];
int n, m, k;
int s, t;

void add(int a, int b, int c)
{
    e[++idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a]= idx;
}

void dijikstra()
{
    memset(dist, 0x3f, sizeof(dist));
    dist[s] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> pq;
    pq.push({0, s});
    while(pq.size())
    {
        PII p = pq.top(); pq.pop();
        int u = p.second;
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = h[u]; ~i; i = ne[i])
        {
            int v = e[i];
            if(dist[v] > dist[u] + w[i])
            {
                dist[v] = dist[u] + w[i];
                pq.push({dist[v], v});
            }
        }
    }
}

int main()
{
    cin >> n >> m >> k;
    cin >> s >> t;
    memset(h, -1, sizeof(h));
    for(int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        for(int j = 0; j <= k; j++) 
        {
            add(u + n * j, v + n * j, w); //将当前层的u->v连起来
            add(v + n * j, u + n * j, w); //将当前层的v->u连起来
        }
        for(int j = 0; j < k; j++) 
        {
            add(u + n * j, v + n * (j + 1), 0); //将当前层的u与下一层的v连起来
            add(v + n * j, u + n * (j + 1), 0); //将当前层的v与下一层的u连起来
        }
    }
    for(int j = 0; j < k; j++) //将相邻层的终点连起来,应对跑到终点花费为0的情况,可以提前走到终点,不需要跳跃所有层
    {
        add(t + n * j, t + n * (j + 1), 0); 
    }
    dijikstra();
    cout << dist[t + n * k];
    return 0;
}

 

posted @ 2025-04-05 00:33  hackerchef  阅读(54)  评论(0)    收藏  举报