题意
\(N\)个小镇,\(M\)条双向道路。第\(i\)条道路从\(a_i\)通向\(b_i\),长度为\(c_i\)。无重边和自环。
车的油箱容量为\(L\),当行驶到一个镇上时可以选择加满油或者什么都不做。行驶单位长度的距离消耗一单位的油。
现在回答\(Q\)个问题:油箱现在为满,从\(s_i\)到\(t_i\),最少需要加油多少次,或者输出无解。
题目链接:https://atcoder.jp/contests/abc143/tasks/abc143_e
数据范围
\(2 \leq N \leq 300\)
思路
首先我们考虑,如果两个地点,它们之间的距离不大于\(L\),那么使用一箱油就可以到达。因此,我们可以按照这个思路去建图。
算法流程如下:
- 首先使用Floyd算法求出任意两点之间的最短路
- 对图进行重构。对于任意两点,如果它们之间的最短距离不超过\(L\),那么边权为\(1\)。
- 再次使用Floyd算法求出任意两点之间在重构图上的最短路
代码
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 310;
const ll INF = 1e18;
int n, m, Q;
ll L;
ll d[N][N];
void floyd()
{
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]);
}
}
}
}
int main()
{
scanf("%d%d%lld", &n, &m, &L);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j ++) {
if(i == j) d[i][j] = 0;
else d[i][j] = INF;
}
}
while(m --) {
int a, b;
ll c;
scanf("%d%d%lld", &a, &b, &c);
d[a][b] = min(d[a][b], c), d[b][a] = d[a][b];
}
floyd();
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= n; j ++) {
if(d[i][j] <= L) d[i][j] = 1;
else d[i][j] = INF;
}
}
floyd();
scanf("%d", &Q);
while(Q --) {
int a, b;
scanf("%d%d", &a, &b);
if(d[a][b] > INF / 2) printf("-1\n");
else printf("%lld\n", d[a][b] - 1);
}
return 0;
}