[CSU 1817 Bones’s Battery Submit]Floyd+二分+思维

[CSU 1817 Bones’s Battery Submit]Floyd+二分+思维

分类:Floyd 二分 思维题

1. 题目链接

[CSU 1817 Bones’s Battery Submit]

2. 题意描述

N 个顶点M条边的无向带权图,边 u v( v u)的权值 w 表示从u v 需要消耗的电量为d。你从0号顶点出发,要求走过所有的顶点。你可以在每个顶点处充满电,但是要求充电的次数不能超过 K ,在保证能走过所有的顶点的情况下,求电池最少的容量。
(2N100,1K100),(0u,v<N,uv,1d109)

3. 解题思路

首先肯定是需要二分答案的。那么关键是如何对二分的当前值判断可行性。
具体步骤如下:
1. 对原图跑一遍floyd,得到顶点之间两两的最短路。
2. 然后开始二分答案。
3. 对二分当前的值(设为 x )进行判断的时候,再开一个二维数组dp[][]:
1. 当u==v的时候,令dp[i][j]=0;
2. 2.当 u v的最短路小于等于 x 的时候,令dp[i][j]=1;
3. 当u v 的最短路大于x的时候,令dp[i][j]=INF;

  1. 对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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值