[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;
}

浙公网安备 33010602011771号