【POJ】3662 - Telephone Lines 二分+最短路

本文解决了一个涉及电线杆连接的问题,通过二分搜索和Dijkstra算法确定了最少费用,以确保两个特定电线杆间的连接,同时考虑了免费电线的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://poj.org/problem?id=3662

一共有N个电线杆,有P对电线杆是可以连接的,现要使得杆1和杆N相连,K条电线可以免费使用的,当使用电线的数量超过K条,超出的电线要收费,收的总费用为去掉免费使用的K条电线之后最长的那条电线的长度。现在需要尽可能的减少费用,问最少费用是多少。

解题思路:可以二分搜索出所需费用,这样,对于每一个最小费用‘候选人’,都要进行判定是否符合题目条件,换句话说,如果以此为最少所需费用,那么至少需要多少条免费使用的电线,这个值与K进行比较,如果比K大,
说明以此为最少所需费用的话还偏小,搜索范围的下界改为当前的费用‘候选人’,反之改上界。在判断至少需要多少条免费使用的电线时,可以使用dijkstra算法,此时点与点之间的距离大于等于‘候选人’时,需要免费使用
的电线数量要加1,否则不用加。

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int INF=0x3f3f3f3f;
const int maxV=1001;
const int maxE=20001;

int N,P,K;
int num=0;
int dis[maxV];
bool vis[maxV];
int head[maxV];

struct Edge{
    int to;
    int val;
    int next;
}e[maxE];

void add(int from,int to,int val){
    e[num].to=to;
    e[num].val=val;
    e[num].next=head[from];
    head[from]=num++;
}

int SPFA(int x){
    queue<int> q;
    memset(vis,false,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));

    dis[1]=0;
    vis[1]=true;
    q.push(1);

    while (!q.empty()){
        int now=q.front();
        vis[now]=false;
        q.pop();
        for (int i=head[now];i!=-1;i=e[i].next){
            int t=dis[now]+(e[i].val>=x?1:0);
            int v=e[i].to;
            if (dis[v]>t){
                dis[v]=t;
                if (!vis[v]){
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }

    return dis[N];
}

int main(){

    cin >> N >> P >> K;
    memset(head,-1,sizeof(head));
    for (int i=0;i<P;i++){
        int from,to,val;
        cin >> from >> to >> val;
        add(from,to,val);
        add(to,from,val);
    }

    int L=0,R=1e6+2;
    while (L+1<R){
        int mid=(L+R)>>1;
        if (SPFA(mid)>K) L=mid;
        else R=mid;
    }
    if (L<=1e6) cout << L << endl;
    else cout << "-1" << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值