poj3662

Description
Farmer John wants to set up a telephone line at his farm. Unfortunately, the phone company is uncooperative, so he needs to pay for some of the cables required to connect his farm to the phone system.
There are N (1 ≤ N ≤ 1,000) forlorn telephone poles conveniently numbered 1…N that are scattered around Farmer John’s property; no cables connect any them. A total of P (1 ≤ P ≤ 10,000) pairs of poles can be connected by a cable; the rest are too far apart.
The i-th cable can connect the two distinct poles Ai and Bi, with length Li (1 ≤ Li ≤ 1,000,000) units if used. The input data set never names any {Ai, Bi} pair more than once. Pole 1 is already connected to the phone system, and pole N is at the farm. Poles 1 and N need to be connected by a path of cables; the rest of the poles might be used or might not be used.
As it turns out, the phone company is willing to provide Farmer John with K (0 ≤ K < N) lengths of cable for free. Beyond that he will have to pay a price equal to the length of the longest remaining cable he requires (each pair of poles is connected with a separate cable), or 0 if he does not need any additional cables.
Determine the minimum amount that Farmer John must pay.

题目大概意思就是给一个图,给出一些可连接的边,同时连接给出这些边的代价,现在要你从点1链接到点n , 同时,你的连接路径上,有k条边是可以选择作为免费边,即这条边依然可以连接,但是费用变为0。现在要求出把一条路径的k条边变为免费之后,剩下的边中,长度最大的边的值最小。

题解:使用二分的方法,二分除了k之外的边的最大值,具体就是有一个二分的mid变量,对于每一个mid,我们把比mid大的边设为1,其他的边全是0,那么跑一遍最短路,把得出的结果与k进行对比,如果比k大,就把往更大二分,如果反之,则更小二分,同时ans记录下mid,然后就是最终答案了。

题解代码:


//
//  main.cpp
//  f
//
//  Created by richard on 2019/3/2.
//  Copyright © 2019年 richard. All rights reserved.
//

//
#include <queue>
#include <bits/stdc++.h>
using namespace std;


queue <int> p;

int n,m,k,ans;
int g[1100][1100],ps[1100][1100];
int d[1100],sign[1100];
int l,r;
int al[110000],bl[100000],cl[100000];

int main () {
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 1;i <= m;i++) {
        scanf("%d%d%d",&al[i],&bl[i],&cl[i]);
    }
    l = 1;r = 500000000;
    while(l <= r) {
        memset(g,-1,sizeof(g));
        memset(d,16,sizeof(d));
        memset(sign,0,sizeof(sign));
        int mid = (l+r)/2;
        for(int i = 1;i <= m;i++) {
            if(cl[i] > mid) {
                g[al[i]][bl[i]] = 1;
                g[bl[i]][al[i]] = 1;
            } else {
                g[al[i]][bl[i]] = 0;
                g[bl[i]][al[i]] = 0;
            }
        }
        d[1] = 0;
        p.push(1);
        sign[1] = 1;
        while(!p.empty()) {
            int t = p.front();
            p.pop();
            sign[t] = 0;
            for(int i = 1;i <= n;i++) {
                if(g[t][i] != -1 && d[t] + g[t][i] < d[i]) {
                    d[i] = d[t] + g[t][i];
                    if(sign[i] == 0) {
                        p.push(i);
                        sign[i] = 1;
                    }
                }
            }
        }
        if(d[n] <= k) {
            r = mid-1;
        } else {
            l = mid+1; 
            ans = mid;
        }

    }
    if(d[n] > 200000000) {
        printf("-1");
        return 0;
    }
    if(ans != 0) {
        ans++;
    }
    printf("%d",ans);
    
    
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值