传送门:>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; }