#E. 架设电线(二分答案经典习题)

该问题是一个关于图论和最优化的计算问题。徐老师需要在电线杆之间架设电线以连接供电所和别墅,已知可以免费使用K对电线杆,其余需要按长度计费。通过二分查找确定最大长度限制,以找到最小成本。算法涉及最短路径计算,判断是否能联通别墅并满足费用条件。
摘要由CSDN通过智能技术生成

题目

说明

徐老师刚新建了一栋别墅,现在他要架设电线给别墅通电。

供电所的编号为 1,徐老师的别墅编号为 N,中间有 N-2 根电线杆,编号依次为 2 ...... N - 1。徐老师对于电量需求很大,需要通过电线杆架设私有电网。由于原先已经架设了很多电线,出于安全考虑,现在只有 P 对电线杆之间能架设电线(我们把供电所和别墅也当成一个电线杆),每一对包含两个电线杆 A_i 和 B_i,在 A_i 和 B_i 之间架设电线需要 L_i 米电线。

现在需要假设电线让供电所和徐老师的别墅能通电。徐老师依靠其强大的个人魅力,争取到让供电所免费帮他在 K 对电线杆直接架设电线,而剩下部分需要收费,收费标准为剩下的需要架设的电线的长度的最大长度。

帮忙计算一下,徐老师最少需要多少钱来架设电线。

输入格式

第一行输入 3 个整数 N(2 <= N <= 1000),P(1 <= P <= 10000),K(0 <= K < N)。

接下来输入 P 行,每行 3 个整数 A_i, B_i(1 <= A_i, B_i <= N),L_i(1 <= L_i <= 10^6),表示 A_i 和 B_i 之间能架设长度为 L_i 的电线。

输出格式

输出徐老师最少需要花费的钱数。如果徐老师的别墅不可能通电,输出 -1。

样例

输入数据 1

5 7 1

1 2 5

3 1 4

2 4 8

3 2 3

5 2 9

3 4 7

4 5 6

输出数据 1

4


思路

很容易想到的是 二分答案check(mid)

然后架设长度<=mid电线,如果可以连通1到n,那么可行,否则不可行

那么k条不需要满足 <= mid电线呢?

对于 长度 <= mid电线,我们可以认为这些电线不花钱

对于 > mid 的电线,我们可以认为这些电线花费为 1

check函数就是从 1 到 n 跑一个最短路,求出 dis[n] ,只要 dis[n] <= k 就意味着 mid 可行


代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,maxn,l,r,mid,dis[10005],ans,u[10005],v[10005],w[10005],t;
int bel(int x)
{
  memset(dis,0x3f,sizeof(dis));
  dis[1] = 0;
  for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
    {
      if(x == -1) t = w[j];
      else if(w[j] <= x) t = 0;
      else t = 1;
      dis[v[j]] = min(dis[v[j]], dis[u[j]] + t);
      dis[u[j]] = min(dis[u[j]], dis[v[j]] + t);
    }
  if (dis[n] == 0x3f3f3f3f3f3f3f3f) return -1;
  else return dis[n];
}
bool f(int n)
{
  if(bel(n) <= k) return 1;
  return 0;
}
signed main()
{
  scanf("%lld%lld%lld",&n,&m,&k);
  for(int i = 1; i <= m; i++)
  {
    scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);
    maxn = max(maxn,w[i]);
  }
  r = maxn;
  if(bel(-1) == -1)
  {
    cout<<-1;
    return 0;
  }
  while(l <= r)
  {
    mid = (l + r) >> 1;
    if(f(mid) == 1)
    {
      r = mid - 1;
      ans = mid;
    }
    else l = mid + 1;
  }
  printf("%lld",ans);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值