题目大意:
给定单向图的n m 为点数和单向边数
接下来m行给定 u v w 为边的起点终点和长度
给定q 为询问个数
接下来q行给定 x y k 求从x到y至少经过k条边的最短路长度
https://blog.csdn.net/qkoqhh/article/details/81301910
设 d[ i ][ j ][ k ] 为从i到j走至少k条边的最短路长度
设 f[ i ][ j ][ k ] 为从i到j恰好走k*100条边的最短路长度
那么至少走K条边的话
若 K>=100 有 f[ i ][ j ][ K/100 ] + d[ i ][ j ][ K%100 ]
若 K%100==0 有 f[ i ][ j ][ K/100 ]
若 K<100 有 d[ i ][ j ][ K ]
最小值就是至少走K条边的最短路
#include <bits/stdc++.h> using namespace std; #define LL long long #define INF 0x3f3f3f3f #define mem(i,j) memset(i,j,sizeof(i)) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int N=50+5; const int M=1e4+5; int n, m; int d[N][N][150], f[N][N][105]; int main() { int _; scanf("%d",&_); while(_--) { scanf("%d%d",&n,&m); inc(i,1,n)inc(j,1,n) d[i][j][1]=INF; while(m--) { int u,v,w; scanf("%d%d%d",&u,&v,&w); d[u][v][1]=min(d[u][v][1],w); // 更新至少1条边的答案 } inc(i,1,n)inc(j,1,n) d[i][j][0]=d[i][j][1]; // 至少0条边的答案应和至少1条相同 inc(i,1,n) d[i][i][0]=0; // 点到本身的距离至少0条边答案肯定为0 inc(k,2,150) { inc(i,1,n)inc(j,1,n) d[i][j][k]=INF; inc(p,1,n)inc(i,1,n)inc(j,1,n) // Floyd d[i][j][k]=min(d[i][j][k],d[i][p][k-1]+d[p][j][1]); } inc(i,1,n)inc(j,1,n) f[i][j][1]=d[i][j][100]; // 按100条边(求了150条)分块应该够了 inc(k,2,100) { inc(i,1,n)inc(j,1,n) f[i][j][k]=INF; inc(p,1,n)inc(i,1,n)inc(j,1,n) // Floyd f[i][j][k]=min(f[i][j][k],f[i][p][k-1]+f[p][j][1]); } dec(k,149,0) inc(i,1,n)inc(j,1,n) d[i][j][k]=min(d[i][j][k],d[i][j][k+1]); // 至少k条边的答案 如果k+1的答案更优 同样可以更新 int q; scanf("%d",&q); while(q--) { int u,v,k; scanf("%d%d%d",&u,&v,&k); int ans=INF; if(k>100) { inc(p,1,n) ans=min(ans,f[u][p][k/100]+d[p][v][k%100]); } if(k%100==0) ans=min(ans,f[u][v][k/100]); if(k<=100) ans=min(ans,d[u][v][k]); if(ans==INF) printf("-1 "); else printf("%d ",ans); } } return 0; }