分层图跑最短路。
但是自己还是太不熟练,没看出来。
太弱了。
对于「选择不多于K条路径并将其长度减半」,实际上可以视为:对于一条路径 $ (u,v) $ ,建两条边:一条到达更高一层的v,权值为 $ w/2 $ ;另一条到达同一层的v,权值为 $ w $ 。
可以发现这个路径是层层升高的。
然后,从起点1跑最短路,取所有层的n中的最短路长度的最小值即可。
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m,k;
int u[500050],v[500050],w[500050],head[500050],nxt[500050],cnt=0;
void add(int ui,int vi,int wi){
cnt++;
nxt[cnt]=head[ui];
head[ui]=cnt;
u[cnt]=ui;
v[cnt]=vi;
w[cnt]=wi;
}
int d[500050];
void spfa(){
bool inq[500050];
memset(inq,0,sizeof inq);
memset(d,0x3f3f,sizeof d);
queue<int>q;
d[1]=0;
inq[1]=1;
q.push(1);
while(!q.empty()){
int ui=q.front();q.pop();
for(int i(head[ui]);i;i=nxt[i]){
int vi=v[i],wi=w[i];
if(d[vi]>d[ui]+wi){
d[vi]=d[ui]+wi;
if(!inq[vi]){
inq[vi]=1;
q.push(vi);
}
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i(1);i<=m;i++){
int ui,vi,wi;scanf("%d%d%d",&ui,&vi,&wi);
for(int j(0);j<=k-1;j++){
add(ui+j*n,vi+j*n,wi);
add(vi+j*n,ui+j*n,wi);
add(ui+j*n,vi+(j+1)*n,wi/2);
add(vi+j*n,ui+(j+1)*n,wi/2);
}
add(ui+k*n,vi+k*n,wi);
add(vi+k*n,ui+k*n,wi);
}
spfa();
int ans=d[n];
for(int i(2);i<=k+1;i++)ans=min(ans,d[n*i]);
printf("%d",ans);
return 0;
}
这里有一点要注意,最后检查每一层n的时候,对应的编号是 $ n,n+n,n+2n,n+3n,......n+kn $
所以最后枚举要到k+1