描述 Description
由于地震使得连接汶川县城的电话线全部损坏,加入你是负责讲电话先接到震中汶川县城的负责人,汶川县城周围分布N(1<=n<=1000)根按1…n电话线杆间可以拉电话线,其余的由于地震使得无法被连接。
第i对电话线杆的两个端点分别为Ai,Ri,它们间的距离为Li(1<=li<=1000000)。数据中保证每对最多只出现一次。编号为1的电话线杆已经接入了全国的电话网络,整个县城的电话线全部连到了编号为N的电话线杆上。也就是说,你的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余的电话线杆并不一定要连入电话网络。
电信公司决定支援灾区免费为汶川县城连接K(0<=k<n)对有你指定的电话线杆。对于此外的那些电话线,需要为它们付费,总费用等于其中最长的电话线长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过K对,那么总支出为0.
请你计算一下,将电话线引到震中汶川县城最少需要在电话线上花多少钱?
第i对电话线杆的两个端点分别为Ai,Ri,它们间的距离为Li(1<=li<=1000000)。数据中保证每对最多只出现一次。编号为1的电话线杆已经接入了全国的电话网络,整个县城的电话线全部连到了编号为N的电话线杆上。也就是说,你的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余的电话线杆并不一定要连入电话网络。
电信公司决定支援灾区免费为汶川县城连接K(0<=k<n)对有你指定的电话线杆。对于此外的那些电话线,需要为它们付费,总费用等于其中最长的电话线长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过K对,那么总支出为0.
请你计算一下,将电话线引到震中汶川县城最少需要在电话线上花多少钱?
输入格式 Input Format
输入文件的第一行包含三个用空格隔开的整数:N P和K。
第二行到第P+1行:每行分别都为三个用空格隔开的整数:Ai Bi和Li。
第二行到第P+1行:每行分别都为三个用空格隔开的整数:Ai Bi和Li。
输出格式 Output Format
输出文件仅包含一个整数,表示在这项工程上的最小支出。如果任务不可能完成,则输出-1.
样例输入 Sample Input [
复制数据]
样例输出 Sample Output [
复制数据]
时间限制 Time Limitation
各个测试点1s
这道题比较好,因为不能用常规的二分思路,否则肯定超时。
普通的思路就是二分出最长的长度,然后搜索检验,n<=1000,果断超时,加之我一开始二分的时候,是二分的[minlen,maxlen]的连续区间,更加慢。若先排序再二分有可能的集合,速度略有优化。仍然过不了。
正确的方法是二分出第K+1长的边,前K长的边都可以直接免费,短于该边的边,因为不影响结果,所以可以不考虑它的长度。
而我们的验证,即是否存在方案,使我们二分出的长度为(第K+1)长或(小于K+1)长。明显去数长度大于二分长度的边最少有多少条!
于是采用最短路!先把长度小于等于二分长度的边临时设为0,大于二分长度的边临时设为1,从1到n求最短路,求出的结果就是长度大于二分长度的边的条数。
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using std::sort;
long mid;
bool used[1010];
long map0[1010][1010];
long map[1010][1010];
long dist[1010];
long c[3010000];
long que[2000010];
long n, k;
const long qmod = 2000000;
long getint()
{
long rs=0;bool sgn=1;char tmp;
do tmp = getchar();
while (!isdigit(tmp)&&tmp-'-');
if (tmp == '-'){tmp=getchar();sgn=0;}
do rs=(rs<<3)+(rs<<1)+tmp-'0';
while (isdigit(tmp=getchar()));
return sgn?rs:-rs;
}
void spfa()
{
memset(dist,0x3f,sizeof dist);
long l = 0;
long r = 0;
r ++;
que[r] = 1;
dist[1] = 0;
while (l < r)
{
l ++;
if (l == qmod)
l = 0;
long u = que[l];
used[u] = false;
for (long v=1;v<n+1;v++)
{
if (map0[u][v]<0x3f3f3f3f && dist[v]>dist[u]+map[u][v])
{
dist[v] = dist[u] + map[u][v];
if (!used[v])
{
used[v] = true;
r ++;
if (r == qmod)
r = 0;
que[r] = v;
}
}
}
}
}
bool can()
{
for (long i=1;i<n+1;i++)
{
for (long j=i;j<n+1;j++)
{
if (map0[i][j] == 0x3f3f3f3f)
map[i][j] = 0x3f3f3f3f;
else if (map0[i][j] <= mid)
map[i][j] = map[j][i] = 0;
else
map[i][j] = map[j][i] = 1;
}
}
spfa();
if (dist[n] > k)
return false;
else
return true;
}
bool check()
{
for (long i=1;i<n+1;i++)
for (long j=i;j<n+1;j++)
map[i][j] = map[j][i] = 1;
spfa();
return dist[n] < 0x3f3f3f3f;
}
int main()
{
freopen("phone.in","r",stdin);
freopen("phone.out","w",stdout);
n = getint();
long p = getint();
k = getint();
memset(map0,0x3f,sizeof map0);
for (long i=1;i<p+1;i++)
{
long a = getint();
long b = getint();
long cc = getint();
map0[a][b] = map0[b][a] = cc;
c[++c[0]] = cc;
}
sort(c+1,c+1+c[0]);
long tmp = 1;
for (long i=2;i<c[0]+1;i++)
if (c[i]!=c[tmp])
c[++tmp] = c[i];
c[0] = 0;
long l = 0;
long r = tmp;
long ans = 0x3f3f3f3f;
if (!check())
{
printf("-1");
return 0;
}
while (l <= r)
{
long mm = (l+r)>>1;
mid = c[mm];
if (can())
{
if (ans > mid)
ans = mid;
r = mm-1;
}
else
{
l = mm+1;
}
}
printf("%ld",ans);
return 0;
}