Telephone Lines POJ3662
投稿日: 更新日:
問題:http://poj.org/problem?id=3662
問題
電柱が本あります。また、ケーブルが本あり、番目のケーブルは電柱と電柱を長さで繋ぐことができます。電柱とを連結させることを考えます。ケーブルは本まで無料で使うことができます。本を超えた場合、超えたケーブルの最大の長さが料金となります。料金は最小でいくらでしょうか。連結できない場合はを出力してください。
解法
以下の料金で電柱とを連結できるか、で二分探索します。
を超える長さのケーブルは無料で利用しなければなりません。その個数が個を超えるかどうかを判定すれば良いことになります。
判定にはダイクストラを用います。各頂点にあと何回無料で使えるかを記録します。実装ではremk
の配列に記録しています。頂点0はとなります。
実装
#include <iostream>
#include <vector>
#include <queue>
#include <utility>
using namespace std;
const int INF = 1e6 + 100;
struct Edge{
int to, l;
Edge(){}
Edge(int to, int l):to(to), l(l){}
};
vector<int> dijkstra(vector<vector<Edge>>& es, int k, int mid){
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> que;
vector<int> remk(es.size(), -1);
remk[0] = k;
que.push(pair<int, int>(k, 0));
while(!que.empty()){
int r = que.top().first;
int v = que.top().second;
que.pop();
if(r < remk[v])continue;
int m = es[v].size();
for(int i = 0;i < m; ++i){
Edge e = es[v][i];
int nrem = remk[v];
if(e.l > mid)nrem--;
if(nrem < 0)continue;
if(remk[e.to] < nrem){
remk[e.to] = nrem;
que.push(pair<int, int>(nrem, e.to));
}
}
}
return remk;
}
int main(){
int n, p, k;
cin >> n >> p >> k;
vector<vector<Edge>> es(n);
for(int i = 0;i < p; ++i){
int a, b, l;
cin >> a >> b >> l;
a--; b--;
es[a].push_back(Edge(b, l));
es[b].push_back(Edge(a, l));
}
int ng = -1, ok = INF;
while(ok - ng > 1){
int mid = (ok+ng)/2;
vector<int> remk = dijkstra(es, k, mid);
if(remk[n-1] >= 0){
ok = mid;
}else{
ng = mid;
}
}
if(ok == INF){
cout << -1 << endl;
}else{
cout << ok << endl;
}
}