http://poj.org/problem?id=3662
一共有N个电线杆,有P对电线杆是可以连接的,现要使得杆1和杆N相连,K条电线可以免费使用的,当使用电线的数量超过K条,超出的电线要收费,收的总费用为去掉免费使用的K条电线之后最长的那条电线的长度。现在需要尽可能的减少费用,问最少费用是多少。
解题思路:可以二分搜索出所需费用,这样,对于每一个最小费用‘候选人’,都要进行判定是否符合题目条件,换句话说,如果以此为最少所需费用,那么至少需要多少条免费使用的电线,这个值与K进行比较,如果比K大,
说明以此为最少所需费用的话还偏小,搜索范围的下界改为当前的费用‘候选人’,反之改上界。在判断至少需要多少条免费使用的电线时,可以使用dijkstra算法,此时点与点之间的距离大于等于‘候选人’时,需要免费使用
的电线数量要加1,否则不用加。
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxV=1001;
const int maxE=20001;
int N,P,K;
int num=0;
int dis[maxV];
bool vis[maxV];
int head[maxV];
struct Edge{
int to;
int val;
int next;
}e[maxE];
void add(int from,int to,int val){
e[num].to=to;
e[num].val=val;
e[num].next=head[from];
head[from]=num++;
}
int SPFA(int x){
queue<int> q;
memset(vis,false,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
vis[1]=true;
q.push(1);
while (!q.empty()){
int now=q.front();
vis[now]=false;
q.pop();
for (int i=head[now];i!=-1;i=e[i].next){
int t=dis[now]+(e[i].val>=x?1:0);
int v=e[i].to;
if (dis[v]>t){
dis[v]=t;
if (!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
return dis[N];
}
int main(){
cin >> N >> P >> K;
memset(head,-1,sizeof(head));
for (int i=0;i<P;i++){
int from,to,val;
cin >> from >> to >> val;
add(from,to,val);
add(to,from,val);
}
int L=0,R=1e6+2;
while (L+1<R){
int mid=(L+R)>>1;
if (SPFA(mid)>K) L=mid;
else R=mid;
}
if (L<=1e6) cout << L << endl;
else cout << "-1" << endl;
}