在一个国家里有 n n n 座城市。这些城市由 m m m 条公交线路连接,其中第 i i i 条线路从城市 a i a_i ai 出发,到 b i b_i bi 停止,路程中耗时 t i t_i ti 分钟。
Ema 喜欢旅行,但她并不喜欢在公交线路之间换乘。在旅行过程中,她希望最多只需坐 k k k 个不同的公交线路。
Ema 想知道,从城市 c i c_i ci 到城市 d i d_i di 的最短旅行时间是多少(最多坐 k k k 个不同的公交线路)。
第一行包含两个整数 n , m n,m n,m,分别表示城市的数量和公交车线路的数量。
接下来 m m m 行,第 i + 1 i+1 i+1 包含三个整数 a i , b i , t i a_i,b_i,t_i ai,bi,ti,分别表示第 i i i 条公交车线路的起点、终点和从起点到终点所需的时间。
接下来一行包含两个整数 k , q k,q k,q,最大坐的不同公交线路的个数和问题题的个数。
接下来 q q q 行,第 m + j + 3 m+j+3 m+j+3 行包含两个整数 c j , d j c_j,d_j cj,dj,表示询问从城市 c j c_j cj 到城市 d j d_j dj 的最短旅行时间。
输出包含 q q q 行,第 i i i 行包含一个整数,表示从城市 c i c_i ci 到城市 d i d_i di 的最短旅行时间。
4 7
1 2 1
1 4 10
2 3 1
2 4 5
3 2 2
3 4 1
4 3 2
1 3
1 4
4 2
3 3
10
-1
0
4 7
1 2 1
1 4 10
2 3 1
2 4 5
3 2 2
3 4 1
4 3 2
2 3
1 4
4 2
3 3
6
4
0
4 7
1 2 1
1 4 10
2 3 1
2 4 5
3 2 2
3 4 1
4 3 2
3 3
1 4
4 2
3 3
3
4
0
【样例解释】
每个样例中的答案都已经标记在图中。
【数据规模与约定】
本题采用子任务捆绑测试。
对于 100 % 100\% 100% 的数据, 2 ≤ n ≤ 70 , 1 ≤ m , t i ≤ 1 0 6 , 1 ≤ a i , b i , c j , d j ≤ n , 1 ≤ k ≤ 1 0 9 , 1 ≤ q ≤ n 2 2\le n \le 70,1\le m,t_i\le 10^6,1\le a_i,b_i,c_j,d_j\le n,1\le k\le10^9,1\le q \le n^2 2≤n≤70,1≤m,ti≤106,1≤ai,bi,cj,dj≤n,1≤k≤109,1≤q≤n2。
【提示与说明】
本题分值按 COCI 原题设置,满分 70 70 70。
题目译自 COCI2021-2022 CONTEST #4 T2 Autobus。
这道题第一眼看过去就像一个最短路,但是加了限制条件:最多坐 k 个线路。那么我们就从最短路入手,我们知道,有很多求最短路的方法,我原本想用效率优秀一点的方法,但是想了一会儿又被自己否决了,因为我发现它们都不太适合这道题(根本原因还是自己太菜了),最终我选择了求全源最短路的弗洛伊德(效率为 O ( n 3 ) O(n^3) O(n3)),毕竟 n 的范围真的很小。
第二个要解决的问题是对 k 的限制,听大佬讲的可以用广义矩阵快速幂,效率为 O ( n 3 l o g n ) O(n^3logn) O(n3logn)但是我比较拉胯,只能写第二种,就是在弗洛伊德外再套上一层循环,从 2 ~ k 枚举,但是要注意k的范围比较大,所以要取 m i n ( k , n ) min(k,n) min(k,n),再用两个数组分别存下上次和这次的答案,最后判断一下输出就行,效率稍差一点,是 O ( n 4 ) O(n^4) O(n4)。
相信弗洛伊德应该都会打,我就不细讲了,就讲一下注意事项好了。
因为数组开的是二维,所以建议要用循环赋值,用memset容易出问题(亲测出锅,改了好久,原本的代码都面目全非了),我的用memset的程序只拿了40分,不过也可能是因为我太弱了才出问题。
还有就是判断的时候因为起点和终点可以相等,所以要特判。
#include
#include
#include
#define maxn 1000010
using namespace std;
template<typename T>void read(T &x){
x=0;
char c=getchar();
T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
long long n,m,k,q;
long long xy[80][80];
long long xxy[80][80],xxyy[80][80];
inline long long minn(int x,int y){
return x<y?x:y;
}
inline void floyd(){
k=min(k,n);
for(int kk=2;kk<=k;kk++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
xxyy[i][j]=xxy[i][j];
}
}
// memcpy(xxyy,xxy,sizeof(xxyy));
for(int l=1;l<=n;l++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
xxyy[i][j]=minn(xxyy[i][j],xxy[i][l]+xy[l][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
xxy[i][j]=xxyy[i][j];
}
}
// memcpy(xxy,xxyy,sizeof(xxy));
}
}
int main(){
read(n),read(m);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
xy[i][j]=0x3f3f3f3f;
}
}
// memset(xy,0x3f3f3f3f,sizeof(xy);
for(int i=1;i<=m;i++){
long long a,b;
int t;
read(a),read(b),read(t);
xy[a][b]=minn(xy[a][b],t);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
xxy[i][j]=xy[i][j];
}
}
// memcpy(xxy,xy,sizeof(xxy));
read(k),read(q);
floyd();
while(q--){
long long c,d;
read(c),read(d);
if(c==d){
printf("0\n");
}
else if(xxy[c][d]==0x3f3f3f3f){
printf("-1\n");
}
else printf("%d\n",xxy[c][d]);
}
return 0;
}