题目链接
题意:n个点m条单向边,一个人每天要从s点走到t点,至少经过k条边,问每天走的最短路径。
考虑邻接矩阵中, a[i][j] a [ i ] [ j ] 表示的是 i i 这个点走到 j j 这个点的距离。这里我们可以认为是 i i 这个点恰好经过 1 1 条边走到 j j 点的最短距离。在做矩阵乘法的时候,用 min(a[i][j],a[i][k]+a[k][j]) m i n ( a [ i ] [ j ] , a [ i ] [ k ] + a [ k ] [ j ] ) 来代替乘法,再套用矩阵快速幂即可达到 i i 到 j j 恰好经过 k k 条边的效果。
但是这样复杂度还是不太够。考虑分块。最多至少经过10000条边,分成 10000‾‾‾‾‾‾√=100 10000 = 100 块,预处理出至少经过100,200,…,10000条边的最短距离和至少经过1,2,3,…,100条边的最短距离。令 K=100X+Y K = 100 X + Y ,则枚举中间经过的点 i i , ans[s][t]=min(ans[s][t],a[s][i]+a[i][t]) a n s [ s ] [ t ] = m i n ( a n s [ s ] [ t ] , a [ s ] [ i ] + a [ i ] [ t ] ) 。而又因为是至少经过 k k 条边,因此要考虑经过超过 k k 条边的情况。在块内,走的边少的情况可以继承走的边多的情况,在块间,除了考虑当前块的情况,还要继承下一个块的值。
#include
using namespace std;
typedef long long ll;
const ll inf=1e18;
int T,n,m,q;
struct Matrix{
ll a[55][55];
Matrix(){
for (int i=0;i<55;i++){
for (int j=0;j<55;j++){
a[i][j]=inf;
}
}
}
Matrix operator * (const Matrix &b) const{
Matrix mat;
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
mat.a[i][j]=min(mat.a[i][j],a[i][k]+b.a[k][j]);
return mat;
}
};
Matrix mat,matrix[110],matrix100[110];
void init(){
matrix[1]=mat;
for (int i=2;i<=101;i++) matrix[i]=matrix[i-1]*matrix[1];
matrix100[1]=matrix[100];
for (int i=2;i<=101;i++) matrix100[i]=matrix100[i-1]*matrix100[1];
for (int k=99;k>=1;k--){
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
matrix[k].a[i][j]=min(matrix[k].a[i][j],matrix[k+1].a[i][j]);
matrix100[k].a[i][j]=min(matrix100[k].a[i][j],matrix100[k+1].a[i][j]);
}
}
}
matrix[0]=matrix[1];
for (int i=0;i<55;i++){
for (int j=0;j<55;j++){
matrix100[0].a[i][j]=inf;
}
}
}
int main(){
scanf("%d",&T);
while (T--){
scanf("%d %d",&n,&m);
for (int i=0;i<54;i++){
for (int j=0;j<54;j++){
mat.a[i][j]=inf;
}
}
for (int i=1;i<=m;i++){
int u,v;
ll w;
scanf("%d %d %lld",&u,&v,&w);
mat.a[u][v]=min(mat.a[u][v],w);
}
init();
scanf("%d",&q);
while (q--){
int s,t,k;
scanf("%d %d %d",&s,&t,&k);
ll ans=inf;
ll x=k/100;
ll y=k%100;
for (int i=1;i<=n;i++){
ans=min(ans,matrix100[x].a[s][i]+matrix[y].a[i][t]);
ans=min(ans,matrix100[x+1].a[s][i]+matrix[0].a[i][t]);
}
if (x==0) ans=min(ans,matrix[y].a[s][t]);
if (y==0) ans=min(ans,matrix100[x].a[s][t]);
if (ans==inf) printf("-1\n");
else printf("%lld\n",ans);
}
}
return 0;
}