[CSU 1817 Bones’s Battery Submit]Floyd+二分+思维
分类:Floyd
二分
思维题
1. 题目链接
[CSU 1817 Bones’s Battery Submit]
2. 题意描述
有
N
个顶点
3. 解题思路
首先肯定是需要二分答案的。那么关键是如何对二分的当前值判断可行性。
具体步骤如下:
1. 对原图跑一遍floyd,得到顶点之间两两的最短路。
2. 然后开始二分答案。
3. 对二分当前的值(设为
x
)进行判断的时候,再开一个二维数组dp[][]:
1. 当
2. 2.当
u
到
3. 当
- 对dp[][]再跑一遍floyd。就可以表示从
u
最少充多少电能到
v , max{dp[u][v]}≤k 则当前值可行,否则不可行。
4. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-6;
const int MAXN = 1e3 + 5;
int T, N, K, M;
LL dist[MAXN][MAXN], dp[MAXN][MAXN];
void floyd(LL ar[][MAXN]) {
for(int i = 0; i < N; ++i) ar[i][i] = 0;
for(int k = 0; k < N; ++k) {
for(int i = 0; i < N; ++i) {
if(ar[i][k] == INFL || i == k) continue;
for(int j = i + 1; j < N; ++j) {
ar[i][j] = ar[j][i] = min(ar[i][j], ar[i][k] + ar[k][j]);
}
}
}
}
bool check(LL x) {
for(int i = 0; i < N; ++i) {
for(int j = i + 1; j < N; ++j) {
if(dist[i][j] == INFL) return false;
dp[i][j] = dp[j][i] = (dist[i][j] <= x) ? 1 : INFL;
}
}
floyd(dp);
for(int i = 0; i < N; ++i) {
for(int j = i + 1; j < N; ++j) {
if(dp[i][j] > K) return false;
}
}
return true;
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
int u, v, w;
scanf("%d", &T);
while(T --) {
scanf("%d %d %d", &N, &K, &M);
memset(dist, 0x3f, sizeof(dist));
while(M --) {
scanf("%d %d %d", &u, &v, &w);
dist[u][v] = dist[v][u] = w;
}
floyd(dist);
LL lb = 0, ub = (1LL << 32) * 100, mid;
while(lb <= ub) {
mid = (lb + ub) >> 1LL;
if(check(mid)) ub = mid - 1;
else lb = mid + 1;
}
printf("%lld\n", lb);
}
return 0;
}