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判断连通性的题目有点类似呢。
/* ***********************************************
Author :111qqz
Created Time :2016年04月02日 星期六 17时50分13秒
File Name :code/bzoj/1614.cpp
************************************************ */
1#include <cstdio>
2#include <cstring>
3#include <iostream>
4#include <algorithm>
5#include <vector>
6#include <queue>
7#include <set>
8#include <map>
9#include <string>
10#include <cmath>
11#include <cstdlib>
12#include <ctime>
13#define fst first
14#define sec second
15#define lson l,m,rt<<1
16#define rson m+1,r,rt<<1|1
17#define ms(a,x) memset(a,x,sizeof(a))
18typedef long long LL;
19#define pi pair < int ,int >
20#define MP make_pair
1using namespace std;
2const double eps = 1E-8;
3const int dx4[4]={1,0,0,-1};
4const int dy4[4]={0,-1,1,0};
5const int inf = 0x3f3f3f3f;
6const int N=1E3+7;
7int n,m,k;
8int d[N];
9bool inq[N];
10vector < pi >edge[N];
1void init()
2{
3 for ( int i = 0 ; i <= n ; i++) edge[i].clear();
}
1int spfa(int X) //X表示最大花费
2{
3 queue<int>q;
4 ms(inq,false);
5 ms(d,0x3f);
6 q.push(1);
7 inq[1] = true;
8 d[1] = 0; // d[i]表示从1到i需要电信公司帮忙建的电话线杆的个数。
1 while (!q.empty())
2 {
3 int u = q.front();
4 q.pop();
5 inq[u] = false;
int siz = edge[u].size();
1 for ( int i = 0 ; i < siz ; i++)
2 {
3 int v = edge[u][i].fst;
4 int w = edge[u][i].sec>X?1:0;
1 if (d[v]>d[u]+w)
2 {
3 d[v] = d[u] + w;
4 if (inq[v]) continue;
5 inq[v] = true;
6 q.push(v);
7 }
8 }
9 }
10 return d[n];
}
1void bin()
2{
3 int l = 0 ;
4 int r = 1000000;
5 int mid;
6 int ans;
1 while (l<=r)
2 {
3 mid = (l+r)/2;
4 if (spfa(mid)<=k) ans = mid,r=mid-1;
5 else l = mid + 1;
6 }
7 printf("%d\n",ans);
8}
9int main()
10{
11 #ifndef ONLINE_JUDGE
12 freopen("code/in.txt","r",stdin);
13 #endif
1 init();
2 scanf("%d%d%d",&n,&m,&k);
3 for ( int i = 1 ; i <= m ; i++)
4 {
5 int u,v,w;
6 scanf("%d%d%d",&u,&v,&w);
7 edge[u].push_back(MP(v,w));//以电话线数目为第一关键字,长度为第二关键字。
8 edge[v].push_back(MP(u,w));
9 }
10 if (spfa(inf)==inf)
11 {
12 puts("-1");
13 return 0;
14 }
15 bin();
1 #ifndef ONLINE_JUDGE
2 fclose(stdin);
3 #endif
4 return 0;
5}