题目
说明
徐老师刚新建了一栋别墅,现在他要架设电线给别墅通电。
供电所的编号为 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;
}