题目链接:点击这里
解题思路:考虑从s走到u至少经过k条路的最少花费可以等价于:
ans[k] = max(f[B][s][i]+F[A][i][u]) i∈[1,n],(A*100 + B = k)
f[B][s][i]表示从s走到i刚好B步的最少花费,F[A][i][u]表示从i走到u至少A*100部的最少花费。
这样就可以把问题变成100的规模来算了。那么最后两个相加就是走至少A*100 + B步的最少花费了。
最后的问题就是最少A*100步的最少花费如何求,刚好100*A步的花费是比较好求的。那么我得再跑一个最短路,加上最短路的值就是至少100*A步的最少花费了。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int mx = 55;
const int N = 105;
const int mod = 1e9 + 7;
typedef long long ll;
int n,m,v[mx][mx];
int F[N][mx][mx],f[N][mx][mx];
int d[mx][mx];
void Get(int a[][mx],int b[][mx],int c[][mx])
{
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
c[i][j] = inf;
for(int k=1;k<=n;k++){
c[i][j] = min(c[i][j],a[i][k]+b[k][j]);
}
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(v,inf,sizeof(v));
int a,b,c;
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
v[a][b] = min(v[a][b],c);
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) F[0][i][j] = f[0][i][j] = i==j? 0:inf;
for(int i=1;i<N;i++) Get(f[i-1],v,f[i]);
for(int i=1;i<N;i++) Get(F[i-1],f[100],F[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) d[i][j] = v[i][j];
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
for(int x=0;x<N;x++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
F[x][i][j] = min(F[x][i][j],F[x][i][k]+d[k][j]);
}
}
}
}
int q;
scanf("%d",&q);
while(q--){
int S,T,K;
scanf("%d%d%d",&S,&T,&K);
int A = K/100,B = K%100;
int ans = inf;
for(int i=1;i<=n;i++) ans = min(ans,F[A][i][T]+f[B][S][i]);
printf("%d\n",ans>=inf?-1:ans);
}
}
return 0;
}