[USACO08JAN]电话线Telephone Lines题解

题目

多年以后,笨笨长大了,成为了电话线布置师。由于地震使得某市的电话线全部损坏,笨笨是负责接到震中市的负责人。该市周围分布着 N(1<=N<=1000) N ( 1 <= N <= 1000 ) 根据1……n顺序编号的废弃的电话线杆,任意两根线杆之间没有电话线连接,一共有 p(1<=p<=10000) p ( 1 <= p <= 10000 ) 对电话杆可以拉电话线。其他的由于地震使得无法连接。第i对电线杆的两个端点分别是ai,bi,它们的距离为 li(1<=li<=1000000) l i ( 1 <= l i <= 1000000 ) 。数据中每对 (ai,bi) ( a i , b i ) 只出现一次。编号为1的电话杆已经接入了全国的电话网络,整个市的电话线全都连到了编号 N N 的电话线杆上。也就是说,笨笨的任务仅仅是找一条将1号和 N N 号电线杆连起来的路径,其余的电话杆并不一定要连入电话网络。电信公司决定支援灾区免费为此市连接k对由笨笨指定的电话线杆,对于此外的那些电话线,需要为它们付费,总费用决定于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过k对,那么支出为0.请你计算一下,将电话线引导震中市最少需要在电话线上花多少钱?
输入输出格式
输入格式:
输入文件的第一行包含三个数字n,p,k;
第二行到第p+1行,每行分别都为三个整数ai,bi,li。
输出格式:
一个整数,表示该项工程的最小支出,如果不可能完成则输出-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

分析

我们正着想不好想,所以我们可以二分再进行判断,我们二分最大费用,将大于的赋1,否则赋0,走1到n的最短路,若大于k,则表示费用小,使l=mid+1,否则 r=mid1 r = m i d − 1 ,这样二分出答案就行了,注意输出-1
上代码

#include<bits/stdc++.h>
using namespace std;
int tot=0,n,p,k,hed[1010],ver[200010],nxt[200010],we[200010],we2[200010],ans,dis[1010];
bool vis[1010];
void add(int x,int y,int z){
    ver[++tot]=y,nxt[tot]=hed[x],hed[x]=tot,we[tot]=z;
}
bool check(int x){
    memset(we2,0,sizeof(we2));
    for(int i=1;i<=tot;i++)
        if(we[i]>x)
            we2[i]=1;
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    queue<int> q;
    q.push(1);
    vis[1]=1,dis[1]=0;
    while(q.size()){
        int y=q.front();
        q.pop();
        vis[y]=0;
        for(int i=hed[y];i;i=nxt[i]){
            int p=ver[i];
            if(dis[p]>dis[y]+we2[i]){
                dis[p]=dis[y]+we2[i];
                if(!vis[p])
                    vis[p]=1,q.push(p);
            }
        }
    }
    if(dis[n]<=k)
        return 1;
    return 0;
}
int main(){
    scanf("%d%d%d",&n,&p,&k);
    for(int i=1,x,y,z;i<=p;i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,z);
    }
    int l=0,r=2000000;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid))
            ans=mid,r=mid-1;
        else
            l=mid+1;
    }
    if((ans==0)&&(r==2000000))
        ans=-1;
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值