bzoj 1614 Telephone Lines架设电话线 - 二分答案 - 最短路

时间:2020-12-09 14:42:10

 

Description

Farmer John打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务。于是,FJ必须为此向电信公司支付一定的费用。 FJ的农场周围分布着N(1 <= N <= 1,000)根按1..N顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相连。一共P(1 <= P <= 10,000)对电话线杆间可以拉电话线,其余的那些由于隔得太远而无法被连接。 第i对电话线杆的两个端点分别为A_i、B_i,它们间的距离为 L_i (1 <= L_i <= 1,000,000)。数据中保证每对{A_i,B_i}最多只出现1次。编号为1的电话线杆已经接入了全国的电话网络,整个农场的电话线全都连到了编号为N的电话线杆上。也就是说,FJ的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余的电话线杆并不一定要连入电话网络。 经过谈判,电信公司最终同意免费为FJ连结K(0 <= K < N)对由FJ指定的电话线杆。对于此外的那些电话线,FJ需要为它们付的费用,等于其中最长的电话线的长度(每根电话线仅连结一对电话线杆)。如果需要连结的电话线杆不超过 K对,那么FJ的总支出为0。 请你计算一下,FJ最少需要在电话线上花多少钱。

Input

* 第1行: 3个用空格隔开的整数:N,P,以及K

 * 第2..P+1行: 第i+1行为3个用空格隔开的整数:A_i,B_i,L_i

Output

* 第1行: 输出1个整数,为FJ在这项工程上的最小支出。如果任务不可能完成, 输出-1

Sample Input

5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6

输入说明:

一共有5根废弃的电话线杆。电话线杆1不能直接与电话线杆4、5相连。电话
线杆5不能直接与电话线杆1、3相连。其余所有电话线杆间均可拉电话线。电信
公司可以免费为FJ连结一对电话线杆。

Sample Output

4

输出说明:

FJ选择如下的连结方案:1->3;3->2;2->5,这3对电话线杆间需要的
电话线的长度分别为4、3、9。FJ让电信公司提供那条长度为9的电话线,于是,
他所需要购买的电话线的最大长度为4。

HINT

 

Source


题目大意

  要从电线杆1连电线一直到电线杆$n$,有$m$对电线杆之间可以连长度为$L_{i}$的电线。运行商可以免去$k$根电线的费用,所付的费用是剩下的电线长度的最大值。问最小的费用。

  原题相当于求最大值的最小值。

  因此二分答案是显然的。

  至于check,用spfa跑出$1$到$n$最少要免的电线的根数,然后可k比大小,完事。

Code

  1 /**
  2  * bzoj
  3  * Problem#1614
  4  * Accepted
  5  * Time: 48ms
  6  * Memory: 1528k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11 
 12 typedef class Edge {
 13     public:
 14         int end;
 15         int w;
 16         int next;
 17         
 18         Edge(int end = 0, int w = 0, int next = 0):end(end), w(w), next(next) {    }
 19 }Edge;
 20 
 21 typedef class MapManager {
 22     public:
 23         int ce;
 24         int *h;
 25         Edge* es;
 26         
 27         MapManager() {        }
 28         MapManager(int n, int m):ce(0) {
 29             h = new int[(n + 1)];
 30             es = new Edge[(m + 5)];
 31             memset(h, 0, sizeof(int) * (n + 1));
 32         }
 33         
 34         void addEdge(int u, int v, int w) {
 35             es[++ce] = Edge(v, w, h[u]);
 36             h[u] = ce;
 37         }
 38         
 39         void addDoubleEdge(int u, int v, int w) {
 40             addEdge(u, v, w);
 41             addEdge(v, u, w);
 42         }
 43         
 44         Edge& operator [] (int pos) {
 45             return es[pos];
 46         }
 47 }MapManager;
 48 
 49 int n, m, k;
 50 int *f;
 51 boolean *vis;
 52 MapManager g;
 53 
 54 inline void init() {
 55     scanf("%d%d%d", &n, &m, &k);
 56     f = new int[(n + 1)];
 57     g = MapManager(n, m << 1);
 58     vis = new boolean[(n + 1)];
 59     for (int i = 1, u, v, w; i <= m; i++) {
 60         scanf("%d%d%d", &u, &v, &w);
 61         g.addDoubleEdge(u, v, w);
 62     }
 63 }
 64 
 65 queue<int> que;
 66 int spfa(int s, int t, int mid) {
 67     memset(vis, false, sizeof(boolean) * (n + 1));
 68     memset(f, 0x3f, sizeof(int) * (n + 1));
 69     que.push(s);
 70     f[s] = 0;
 71     while (!que.empty()) {
 72         int e = que.front();
 73         que.pop();
 74         vis[e] = false;
 75         for (int i = g.h[e]; i; i = g[i].next) {
 76             int eu = g[i].end, c = (g[i].w > mid) ? (1) : (0);
 77             if (f[e] + c < f[eu]) {
 78                 f[eu] = f[e] + c;
 79                 if (!vis[eu]) {
 80                     que.push(eu);
 81                     vis[eu] = true;
 82                 } 
 83             }
 84         }
 85     }
 86     return f[t];
 87 }
 88 
 89 inline void solve() {
 90     int l = 0, r = 1e6 + 1;
 91     while (l <= r) {
 92         int mid = (l + r) >> 1;
 93         if (spfa(1, n, mid) <= k)
 94             r = mid - 1;
 95         else
 96             l = mid + 1;
 97     }
 98     printf("%d\n", (r > 1e6) ? (-1) : (r + 1));
 99 }
100 
101 int main() {
102     init();
103     solve();
104     return 0;
105 }