P1948 [USACO08JAN] Telephone Lines S

发布于:2025-08-04 ⋅ 阅读:(15) ⋅ 点赞:(0)

P1948 [USACO08JAN] Telephone Lines S

题目描述

多年以后,笨笨长大了,成为了电话线布置师。由于地震使得某市的电话线全部损坏,笨笨是负责接到震中市的负责人。该市周围分布着 nnn1≤n≤1031\le n\le10^31n103)根按 1∼n1\sim n1n 顺序编号的废弃的电话线杆,任意两根线杆之间没有电话线连接,一共有 ppp1≤p≤1041\le p\le10^41p104)对电话杆可以拉电话线。其他的由于地震使得无法连接。

第i对电线杆的两个端点分别是 ai,bia_i,b_iai,bi,它们的距离为lil_ili1≤li≤1061\le l_i\le10^61li106)。数据中每对 (ai,bi)(a_i,b_i)(ai,bi) 只出现一次。编号为 111 的电话杆已经接入了全国的电话网络,整个市的电话线全都连到了编号 nnn 的电话线杆上。也就是说,笨笨的任务仅仅是找一条将 111 号和 nnn 号电线杆连起来的路径,其余的电话杆并不一定要连入电话网络。

电信公司决定支援灾区免费为此市连接 kkk1≤k≤p1\le k\le p1kp)对由笨笨指定的电话线杆,对于额外的那些电话线,需要为它们付费,总费用决定于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过 kkk 对,那么支出为 000

请你计算一下,将电话线引导震中市最少需要在电话线上花多少钱?

输入格式

输入文件的第一行包含三个数字 n,p,kn,p,kn,p,k

第二行到第 p+1p+1p+1 行,每行分别都为三个整数 ai,bi,lia_i,b_i,l_iai,bi,li

输出格式

一个整数,表示该项工程的最小支出,如果不可能完成则输出 −1-11

输入输出样例 #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

题目要求花费最小值,可以察觉到能利用二分答案求解。
我们记录下所有边中最大的修复代价作为 rrr。随后我们希望在 check 中检查当前的二分结果是否合法——找到一条最短路,其中需要进行修复的路小于等于 kkk。这里我们可以将代价转换为消耗的免费修复次数distdistdist。如果从 1 到 n 的dist<=kdist<=kdist<=k,则说明当前二分答案可行,check 返回 truetruetrue

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

bool check(int mid, int n, int k, vector<vector<pair<int, int>>>& g){
    vector<int> dist(n+1, INT_MAX);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;
    dist[1] = 0;
    pq.emplace(0, 1);
    while (!pq.empty()) {
        auto [d, u] = pq.top();
        pq.pop();
        if (d > dist[u]) continue;
        for (auto& edge : g[u]) {
            int v = edge.first;
            int len = edge.second;
            int cost = (len > mid) ? 1 : 0;

            if (dist[v] > dist[u] + cost) {
                dist[v] = dist[u] + cost;
                pq.emplace(dist[v], v);
            }
        }
    }
    return dist[n]<=k;
}

int main(){
    int n, p, k;
    cin>>n>>p>>k;
    vector<vector<pair<int, int>>> g(n+1);
    int l = 0, r = 0, mid = 0;
    for(int i = 0;i<p;i++){
        int a, b, len;
        cin>>a>>b>>len;
        g[a].emplace_back(b, len);
        g[b].emplace_back(a, len);
        if(len>r) r = len; 
    }
    int ans = -1;
    while(l<=r){
        mid = (l + r)/2;
        if(check(mid, n, k, g)){
            r = mid - 1;
            ans = mid;
        }else {
            l = mid + 1;
        }
    }
    cout<<ans;
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到