Travel by Car(Floyd)

题意

\(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;
}
posted @ 2022-07-08 10:34  pbc的成长之路  阅读(62)  评论(0)    收藏  举报