[JLOI2011] 飞行路线

传送门:>HERE<

题意:给出一张无向图,可以选择跳过(权值改没0)条边,问从s到t的最短路

解题思路

  这真是一道趣题。乍一看以为是求个最短路,然后减去最大的k条边。然而样例就是一个这种方法的反例——跳过一条原本很长的边也许可以省去好多条最短路内的边。这就让问题复杂化了

  想办法转化为会求解的普通单源最短路:分层图思想

  建立k张图,第i张图表示跳过了i条路径的。最后的答案就是每一层的图的d[t]的最小值。因此只要建好分层图,直接跑dijkstra就好了。如何建立呢?图与图之间每一层连得边权值为0. 那么只需要每一层都正常建,同时相邻的两张图交叉连一下权值为0的边就好了

Code

  SPFA被卡,乖乖dijkstra吧

  另外,数组要开大(BZOJ是正常的报的是RE,luogu竟然莫名其妙报是TLE)

/*by DennyQi*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define  r  read()
#define  Max(a,b)  (((a)>(b))?(a):(b))
#define  Min(a,b)  (((a)<(b))?(a):(b))
using namespace std;
typedef long long ll;
const int MAXN = 600010;
const int MAXM = 2000010;
const int INF = 0x3f3f3f3f;
const int MOD = 998244353;
inline int read(){
    int x = 0; int w = 1; register unsigned char c = getchar();
    for(; c^'-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0';
    return x * w;
}
struct Node{
    int idx,w;
};
bool operator < (Node a, Node b){
    return a.w > b.w;
}
int N,M,K,s,t,x,y,z;
int first[MAXM*2],next[MAXM*2],to[MAXM*2],cost[MAXM*2],num_edge;
int d[MAXN],vis[MAXN];
priority_queue <Node> q;
inline void add(int u, int v, int w){
//    printf("%d->%d (%d)
",u,v,w);
    to[++num_edge] = v;
    cost[num_edge] = w;
    next[num_edge] = first[u];
    first[u] = num_edge;
}
inline void Dijkstra(int s){
    memset(d, 0x3f, sizeof(d));
    int u,v;
    d[s] = 0;
    q.push((Node){s, 0});
    while(!q.empty()){
        u = q.top().idx; q.pop();
        if(vis[u]) continue;
//        printf("u = %d
", u);
        vis[u] = 1;
        for(int i = first[u]; i; i = next[i]){
            v = to[i];
//            printf("%d-> %d
",u,v);
            if(d[u] + cost[i] < d[v]){
                d[v] = d[u] + cost[i];
                q.push((Node){v, d[v]});
            }
        }
    }
}
int main(){
//    freopen(".in", "r", stdin);
    N=r,M=r,K=r;
    s=r,t=r;
    for(int i = 1; i <= M; ++i){
        x=r,y=r,z=r;
        add(x,y,z);
        add(y,x,z);
        for(int k = 0; k < K; ++k){
            add(x + k * N, y + (k+1) * N, 0);
            add(y + k * N, x + (k+1) * N, 0);
            add(x + (k+1) * N, y + (k+1) * N, z);
            add(y + (k+1) * N, x + (k+1) * N, z);
        }
    }
    Dijkstra(s);
/*    for(int i = 0; i <= N*(K+2); ++i){
        printf("d[%d] = %d
",i,d[i]);
    }*/
    int ans = INF;
    for(int k = 0; k <= K; ++k){
        ans = Min(ans, d[t + k * N]);
    }
    printf("%d", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/qixingzhi/p/9390347.html