在郊区有 N N N 座通信基站, P P P 条双向电缆,第 i i i 条电缆连接基站 A i A_i Ai 和 B i B_i Bi。农场主希望对通信线路进行升级,其中升级第 i i i 条电缆需要花费 L i L_i Li。
电话公司正在举行优惠活动。农场主可以指定一条从 1 1 1 号基站到 N N N 号基站的路径,并指定路径上不超过 K K K 条电缆,由电话公司免费提供升级服务。农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。求至少用多少钱能完成升级。
解
二分。
二分最贵的电缆,然后比它贵的就需要免费,边权为 1,小于等于它的就不需要免费。
然后跑 SPFA,求出最少需要免费多少。
然后看一下题目给的免费够不够,就可以判断这个作为最贵的电缆是否可行了。
代码
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int n, p, k, t, u, v, ll, rr, mid, l[1003], w, in[1003], vvv[1003], maxx;
struct klx{
int to, z, next;
} a[30005];
int read(){
char c = getchar();
long long xx = 0;
while(c > '9' || c < '0') c = getchar();
while(c <= '9' && c >= '0'){
xx = xx * 10 + c - 48;
c = getchar();
}
return xx;
}
void spfa(){
queue<int> Q;
memset(vvv, 0x7f, sizeof(vvv));
memset(in, 0, sizeof(in));
Q.push(n);
vvv[n] = 0;
while(!Q.empty()){
int d = Q.front();
Q.pop();
in[d] = 0;
for(int i = l[d]; i; i = a[i].next){
if(a[i].z <= mid && vvv[a[i].to] > vvv[d]){ //小于等于,无需免费
vvv[a[i].to] = vvv[d];
if(in[a[i].to] == 0){
in[a[i].to] = 1;
Q.push(a[i].to);
}
}
if(a[i].z > mid && vvv[a[i].to] > vvv[d]+1){ //大于,需要免费
vvv[a[i].to] = vvv[d] + 1;
if(in[a[i].to] == 0){
in[a[i].to] = 1;
Q.push(a[i].to);
}
}
}
}
}
int main(){
freopen("phone.in","r",stdin);
freopen("phone.out","w",stdout);
n = read();
p = read();
k = read();
for(int i = 1; i <= p; ++i){
u = read();
v = read();
w = read();
a[++t] = (klx){v, w,l[u]}; l[u] = t;
a[++t] = (klx){u, w,l[v]}; l[v] = t;
rr = max(rr, w);
}
++rr;
maxx = rr;
while(ll < rr){
mid = (ll+rr) >> 1;
spfa();
if(k >= vvv[1]) rr = mid; //可以免费个数够
else ll = mid+1; //不够,就不行
}
if(rr == maxx) printf("-1");
else printf("%d", ll);
fclose(stdin);
fclose(stdout);
}