题目:一个有向图,q组询问,每组询问(x,y,z)问从x到y至少经过z条路时的最短路径。
思路:
w[i][j]表示从i到j恰好经过1条路径的最短长度(就是原图)。
dpa[t][i][j]表示从i到j恰好经过t条路径的最短长度。
dpb[t][i][j]表示从i到j恰好经过100∗t条路径的最短长度。
最后floyd来更新dpb数组得到至少经过100∗t条道路的最短路.
ans=min(dpb[k/100][x][i]+dpa[k%100][i][y]);
#include<bits/stdc++.h>
using namespace std;
int w[55][55],tmp[55][55];
int dpa[110][55][55],dpb[110][55][55];
int n,m;
int dis[55][55];
void solve(int a[][55],int b[][55],int ans[][55])
{
memset(dis,0x3f,sizeof dis);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],a[i][k]+b[k][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ans[i][j]=dis[i][j];
}
int T,q;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(w,0x3f,sizeof w);
int inf=w[0][0];
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
w[x][y]=min(w[x][y],z);///可能有重边
}
memset(dpa,0x3f,sizeof dpa);
memset(dpb,0x3f,sizeof dpb);
for(int i=1;i<=n;i++)
dpa[0][i][i]=dpb[0][i][i]=0;
memcpy(dpa[1],w,sizeof dpa[1]);
for(int i=2;i<=100;i++)
solve(dpa[i-1],w,dpa[i]);
memcpy(dpb[1],dpa[100],sizeof dpb[1]);
for(int i=2;i<=100;i++)
solve(dpb[i-1],dpa[100],dpb[i]);
for(int i=1;i<=n;i++)
w[i][i]=0;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=min(w[i][j],w[i][k]+w[k][j]);
for(int t=0;t<=100;t++)
{
memset(tmp,0x3f,sizeof tmp);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
tmp[i][j]=min(tmp[i][j],dpb[t][i][k]+w[k][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dpb[t][i][j]=min(dpb[t][i][j],tmp[i][j]);
}
scanf("%d",&q);
while(q--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int ans=inf;
for(int i=1;i<=n;i++)
{
//printf("%d %d\n",dpb[z/100][x][i],dpa[z%100][i][y]);
ans=min(ans,dpb[z/100][x][i]+dpa[z%100][i][y]);
}
if(ans==inf) puts("-1");
else printf("%d\n",ans);
}
}
return 0;
}