gg给的题解
这道题的k很小,把k看作一种状态,可以考虑用分层的方法解决。
把每个点分成k个,dis[x][k] 代表使用了k次免费机会,到达x的最短距离。
从u到v,可以不使用免费机会,费用为val,或者使用免费机会,边权为0。
那么连边的时候,每条边实际要连2*(k+1)条:(i = 0~k) 从[x][i]到[y][i],边权为val;从[x][i]到[y][i+1],边权为0。
然后直接跑最短路就可以了。
实际写的时候不需要开二维数组,因为一共有(n+1)*(k+1)个点(n,k都从0开始),
所以把点的编号记作x+i*n即可。
代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq #include<queue> using namespace std; const int maxn = 1e7+10; const int INF = 0x3f3f3f3f; int n,m,k,s,t,a,b,c; int head[maxn],to[maxn],nxt[maxn],val[maxn]; int dis[maxn],cnt,ans; bool vis[maxn]; void add(int x,int y,int z) { to[++cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; val[cnt] = z; } void init() { for(int i = 0; i <= n; i++) for(int j = 0; j <= k; j++) dis[i+j*n] = INF; } void dijkstra(int s) { init(); priority_queue < pair < int,int > , vector < pair < int,int > >,greater < pair < int,int > > > q; dis[s] = 0; q.push(make_pair(0,s)); while(!q.empty()) { int u = q.top().second; q.pop(); if(vis[u])continue; vis[u] = true; for(int i = head[u]; i; i = nxt[i]) { int v = to[i]; if(dis[u] + val[i] < dis[v]) { dis[v] = dis[u] + val[i]; q.push(make_pair(dis[v],v)); } } } } int main() { scanf("%d%d%d",&n,&m,&k); scanf("%d%d",&s,&t); for(int i = 1; i <= m; i++) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); for(int j = 1; j <= k; j++) { add(a+j*n,b+j*n,c); add(b+j*n,a+j*n,c); add(a+(j-1)*n,b+j*n,0); add(b+(j-1)*n,a+j*n,0); } } dijkstra(s); ans = INF; for(int i = 0; i <= k; i++) ans = min(ans,dis[t+i*n]); printf("%d",ans); return 0; }