[ABC257D] Jumping Takahashi 2

主要算法

全源最短路(改版)。

题意

此题要求从某一个点到其他任意的点的路径上的最大边权的最小值。

思路

第一步

计算边权,用两点的曼哈顿距离 $dis$ 去除以出发蹦床的系数 $P_i$,为了满足跳得过去且 $S$ 为整数,所以边权为 $\left \lceil \frac{dis}{P_i} \right \rceil $。

第二步

计算从 $u$ 到 $v$ 点路径上的最小的最大的边权,可以用修改的 Floyd 算法,用 $O(n^3)$ 的时间复杂度解决此步骤。

转移方程为:$need_{i,j} = \min(need_{i,j}, \max(need_{i,k}, need_{k,j}))$。

就是把从 $i$ 到 $j$ 的路径分为 $i$ 到 $k$ 的与 $k$ 到 $j$ 的路径,取其路径上的最大值,并与原来的值比较以找到最小边权。

第三步

枚举每一个点,从所有点中暴力找出到其他点路径上最大边权最小的点,输出它到其他点路径上最大边权即可。

注意事项

一定要全部开 long long!

Code

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define endl '\n'

typedef long long ll;
typedef double db;
const int M = 200 + 10;
const int mod = 1e9 + 7;

int n;
ll x[M], y[M], s[M];
ll need[M][M];//路径上的最大边权

signed main() {
    ios::sync_with_stdio(0);
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> x[i] >> y[i] >> s[i];
    memset(need, 0x3f, sizeof need);//初始化
    for (int i = 1; i <= n; i ++){
        for (int j = 1; j <= n; j ++){
            ll dis = abs(x[i] - x[j]) + abs(y[i] - y[j]);
            need[i][j] = ceil((db)dis / (db)s[i]);
            need[j][i] = ceil((db)dis / (db)s[j]);//计算初始边权
        }
    }
    for (int k = 1; k <= n; k ++){
        for(int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                need[i][j] = min(need[i][j], max(need[i][k], need[k][j]));//Floyd 求两点之间的最小路径上的边
    }
    ll ans = LINF;
    for (ll i = 1, maxn; i <= n; i ++){//找最大权最小的点
        maxn = -1;
        for (int j = 1; j <= n; j ++)
            maxn = max(maxn, need[i][j]);
        ans = min(ans, maxn);
    }
    cout << ans << endl;
    return 0;
}
posted @ 2023-10-28 16:25  固态H2O  阅读(29)  评论(0)    收藏  举报  来源