[JLOI2011]飞行路线

题目【拆点】【分层图】【最短路】

思路

  • 拆点: 将一个状态 拆为 k+1 个状态
  • 原来dijkstra(dist, j)
  • 现在拆成k+1个状态, 状态变为(dist, j, cnt) cnt为当前已免费使用的次数

代码(dijkstra + 拆点)

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

const int N = 10010, M = 100010;
int h[N], e[M], w[M], ne[M], idx;
int n, m, k;
struct State{
    int u, dist, cnt;
    bool operator<(const State& t) const {
        return dist > t.dist;
    }
};
bool st[N][11];
int dist[N][11];//拆点
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 dijkstra() {
    priority_queue<State> pq;
    pq.push({S, 0, 0});
    memset(dist, 0x3f, sizeof dist);
    dist[S][0] = 0;
    
    while(pq.size()) {
        auto t = pq.top(); pq.pop();
        int u=t.u, cnt=t.cnt;
        
        if(st[u][cnt]) continue;
        st[u][cnt] = true;
        
        for(int i=h[u]; ~i; i=ne[i]) {
            int j = e[i];
            //1 走w=0
            if(cnt < k && dist[j][cnt+1] > dist[u][cnt]) {
                dist[j][cnt+1] = dist[u][cnt];
                pq.push({j,dist[j][cnt+1],cnt+1});
            }
            //2 走w=w
            if(dist[j][cnt] > dist[u][cnt] + w[i]) {
                dist[j][cnt] = dist[u][cnt] + w[i];
                pq.push({j, dist[j][cnt], cnt});
            }
        }
    }
}

int main()
{
    memset(h, -1, sizeof h);
    cin>>n>>m>>k;
    cin>>S>>T;
    while(m--) {
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        add(a,b,c);
        add(b,a,c);
    }
    dijkstra();
    int res = INT_MAX;
    for(int i=0; i<=k; ++i) res = min(res, dist[T][i]);
    cout<<res;
    return 0;
}
posted @ 2021-08-24 22:22  misaka-mikoto  阅读(36)  评论(0编辑  收藏  举报