http://acm.hdu.edu.cn/showproblem.php?pid=6331
f[k][i][j]=min(f[k][i][j],f[k+1][i][j]) 这个式子是关键 通过该式子可以n^3的求出从i到j恰好走几步的最短距离
可以跑2e4次n^3 从后向前取最小值 即f[k][i][j]=min(f[k][i][j],f[k+1][i][j])
但是查询的k是1e4 还需要分块 就是把k分为k%100与k/100 前者只需要取恰好多少步的最短距离 后者取至少多少步的最短距离
至于为什么求至少多少步时需要多求很多次 因为两点之间的最短距离在最坏情况之下需要(n-1)次才可以求出 而在求出这个最优值之前 所有用此两点之间距离去松弛的操作都不会得到最优解
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f
ll e[60][60],fa[110][60][60],fb[210][60][60];
int n,m,q;
void getmul(ll a[][60],ll b[][60],ll c[][60])
{
ll t[60][60];
int i,j,k;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
t[i][j]=N;
for(k=1;k<=n;k++)
{
t[i][j]=min(t[i][j],a[i][k]+b[k][j]);
}
}
}
memcpy(c,t,sizeof(t));
}
void solve()
{
int i,j,k;
memcpy(fb[1],e,sizeof(e));
for(i=2;i<=200;i++)
{
getmul(e,fb[i-1],fb[i]);
}
memcpy(fa[1],fb[100],sizeof(e));
for(i=2;i<=100;i++)
{
getmul(fb[100],fa[i-1],fa[i]);
}
for(k=199;k>=1;k--)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
fb[k][i][j]=min(fb[k][i][j],fb[k+1][i][j]);
}
}
}
}
ll query(int u,int v,int a,int b)
{
ll res;
int i;
res=N;
for(i=1;i<=n;i++)
{
res=min(res,fa[a][u][i]+fb[b][i][v]);
}
return res;
}
int main()
{
ll w,res;
int t,i,j,u,v,k,a,b;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(e,0x3f,sizeof(e));
for(i=1;i<=m;i++)
{
scanf("%d%d%lld",&u,&v,&w);
e[u][v]=min(e[u][v],w);
}
solve();
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d",&u,&v,&k);
if(k<=100)
{
if(fb[k][u][v]==N) printf("-1\n");
else printf("%lld\n",fb[k][u][v]);
}
else
{
a=(k-1)/100,b=k-100*a;
res=query(u,v,a,b);
if(res==N) printf("-1\n");
else printf("%lld\n",res);
}
}
}
return 0;
}