电话网络
[题目描述]
由于地震使得连接汶川县城电话线全部损坏,假如你是负责将电话线接到震中汶川县城的负责人,汶川县
城周围分布着 N(1≤N≤1,000)根按 1..N 顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相
连。一共 P(1≤P≤10,000)对电话线杆间可以拉电话线,其余的由于地震使得无法被连接。
第 i 对电话线杆的两个端点分别为 Ai,Bi,它们间的距离为 Li(1≤Li≤1,000,000)。数据中保证每对
(Ai,Bi)最多只出现 1 次。编号为 1 的电话线杆已经接人了全国的电话网络,整个县城的电话线全都连到了编
号为 N 的电话线杆上。也就是说,你的任务仅仅是找一条将 1 号和 N 号电话线杆连起来的路径,其余的电话线
杆并不一定要连人电话网络。
电信公司决定支援灾区免费为汶川县城连结 K(0≤K<N)对由你指定的电话线杆。对于此外的那些电话线,需要
为它们付费,总费用等于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线
杆不超过 K 对,那么总支出为 0。
请你计算一下,将电话线引到震中汶川县城最少需要在电话线上花多少钱?
[输入格式]
输入文件的第一行包含三个用空格隔开的整数:N,P 和 K。
第二行到第 P+1 行:每行分别都为空格隔开的整数:Ai,Bi 和 Li。
[输出格式]
输出文件中仅包含一个整数,表示在这项工程上的最小支出。如果任务不可能完成,则输出-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
[输出样例]
4
这个题怎么做?初看感觉好像没有任何思路。当时因为要求最小值,那么就想到了二分答案这样一种方法。但是当时没有想到的是如何二分,如果直接跑最短路显然不行,但是我们可以跑的是最短路上有多少条比当前二分的值边权大的边。直接对每一条边赋值即可,如果边权大于当前二分的值就赋为1否则为0,之后把这个当边权跑最短路即可。这样的话,我们就不停的二分答案就好了。
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') #define inf 2147483647 using namespace std; typedef long long ll; const int M = 100005; int n,p,k,a,b,c,head[M],dis[M],cnt,r = M*10,l; bool vis[M],flag,pd[M]; queue <int> q; struct node { int to,next,v,w; }e[M]; inline int read() { int as = 0,fu = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') fu = -1; c = getchar(); } while(c >= '0' && c <= '9') { as = as * 10 + c - '0'; c = getchar(); } return as * fu; } void add(int x,int y,int z) { e[++cnt].to = y; e[cnt].v = z; e[cnt].next = head[x]; head[x] = cnt; } void spfa(int s) { dis[s] = 0,vis[s] = 0;q.push(s); while(!q.empty()) { int now = q.front();q.pop(),vis[now] = 0; for(int i = head[now];i;i = e[i].next) { if(dis[now] + e[i].w < dis[e[i].to]) { dis[e[i].to] = dis[now] + e[i].w; if(!vis[e[i].to]) q.push(e[i].to),vis[e[i].to] = 1; } } } } int main() { freopen("phone.in","r",stdin); freopen("phone.out","w",stdout); n = read(),p = read(),k = read(); rep(i,1,p) { a = read(),b = read(),c = read(); add(a,b,c); add(b,a,c); } while(l < r) { int mid = (l+r) >> 1; rep(i,1,cnt) { if(e[i].v > mid) e[i].w = 1; else e[i].w = 0; } rep(i,1,n) dis[i] = inf; spfa(1); if(dis[n] == inf) printf("-1\n"),exit(0); // printf("%d %d\n",mid,dis[n]); if(dis[n] > k) l = mid + 1; else r = mid; } printf("%d\n",l); return 0; }