BZOJ 1614: [Usaco2007 Jan]Telephone Lines架设电话线 (二分+spfa)
1614: [Usaco2007 Jan]Telephone Lines架设电话线
Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1325 Solved: 570 [Submit][Status][Discuss]
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
思路:一开始把电话线条数和长度分别作为第一第二关键字,然后spfa.然后记录路径,找k个最大的以后的中最长的电话线就是答案。发现样例就是反例。。智力-2.
正确的做法是二分电话线的最大长度,大于最大长度的电话线交给电信公司取搞,看交给电信公司搞的电话线数目是否小于等于k.
二分的功夫还是不到家呀。。想不到。。 不过这道题和那个中国印度被喜马拉雅山脉阻隔,二分+bfs判断连通性的题目有点类似呢。
1/* ***********************************************
2Author :111qqz
3Created Time :2016年04月02日 星期六 17时50分13秒
4File Name :code/bzoj/1614.cpp
5************************************************ */
6
7#include <cstdio>
8#include <cstring>
9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define fst first
20#define sec second
21#define lson l,m,rt<<1
22#define rson m+1,r,rt<<1|1
23#define ms(a,x) memset(a,x,sizeof(a))
24typedef long long LL;
25#define pi pair < int ,int >
26#define MP make_pair
27
28using namespace std;
29const double eps = 1E-8;
30const int dx4[4]={1,0,0,-1};
31const int dy4[4]={0,-1,1,0};
32const int inf = 0x3f3f3f3f;
33const int N=1E3+7;
34int n,m,k;
35int d[N];
36bool inq[N];
37vector < pi >edge[N];
38
39void init()
40{
41 for ( int i = 0 ; i <= n ; i++) edge[i].clear();
42
43}
44
45int spfa(int X) //X表示最大花费
46{
47 queue<int>q;
48 ms(inq,false);
49 ms(d,0x3f);
50 q.push(1);
51 inq[1] = true;
52 d[1] = 0; // d[i]表示从1到i需要电信公司帮忙建的电话线杆的个数。
53
54
55 while (!q.empty())
56 {
57 int u = q.front();
58 q.pop();
59 inq[u] = false;
60
61 int siz = edge[u].size();
62
63 for ( int i = 0 ; i < siz ; i++)
64 {
65 int v = edge[u][i].fst;
66 int w = edge[u][i].sec>X?1:0;
67
68 if (d[v]>d[u]+w)
69 {
70 d[v] = d[u] + w;
71 if (inq[v]) continue;
72 inq[v] = true;
73 q.push(v);
74 }
75 }
76 }
77 return d[n];
78
79}
80
81void bin()
82{
83 int l = 0 ;
84 int r = 1000000;
85 int mid;
86 int ans;
87
88 while (l<=r)
89 {
90 mid = (l+r)/2;
91 if (spfa(mid)<=k) ans = mid,r=mid-1;
92 else l = mid + 1;
93 }
94 printf("%d\n",ans);
95}
96int main()
97{
98 #ifndef ONLINE_JUDGE
99 freopen("code/in.txt","r",stdin);
100 #endif
101
102 init();
103 scanf("%d%d%d",&n,&m,&k);
104 for ( int i = 1 ; i <= m ; i++)
105 {
106 int u,v,w;
107 scanf("%d%d%d",&u,&v,&w);
108 edge[u].push_back(MP(v,w));//以电话线数目为第一关键字,长度为第二关键字。
109 edge[v].push_back(MP(u,w));
110 }
111 if (spfa(inf)==inf)
112 {
113 puts("-1");
114 return 0;
115 }
116 bin();
117
118 #ifndef ONLINE_JUDGE
119 fclose(stdin);
120 #endif
121 return 0;
122}