P1948 [USACO08JAN]Telephone Lines S
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<stdlib.h>
#include <math.h>
#define LL long long
using namespace std;
const int N = 100010;
int head[1010], cnt = 0, dis[1010], vis[1010];
int k, n, m, mx;
//二分答案+dijkstra
//因此,我们可以二分最大的花费x,x属于[l, r], (l为最小花费,r为最大花费), x然后将大于x的边看做权值为1的边,将小于等于x的边看做权值为零的边,
//然后找到从点1到点n的最短路,若最短路的长度大于k,则要连接的对数大于k对,在[x + 1, r]中继续二份查找;若最短路的长度小于k,
//则要连接的对数比k小,在[l, x]中继续二份查找,最终,l即为所求。
struct node {
int nxt;
int val;
int to;
}e[N];
struct priority//运用优先队列(堆)来实现优化
{
long long ans;//存储可用的ans值
int id;
bool operator <(const priority& x) const//重载<号,使其可以使用优先队列
{
return x.ans < ans;
}
};
priority_queue <priority> q;
inline void add(int u, int v, int w) {
e[++cnt].to = v;
e[cnt].val = w;
e[cnt].nxt = head[u];
head[u] = cnt;
}
bool dijkstra(int s, int mid, int k) {
int u;
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[1] = 0;
q.push({ 0,1 });
while (!q.empty()) {
priority t = q.top();
u = t.id;
q.pop();
if (!vis[u]) {
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to, w = (e[i].val > mid ? 1 : 0);//判断是否大于免费费用,如果大于,则免费,同时w记为1,表示增加一条免费边
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {//防止重复入队
q.push({ dis[v], v });
}
}
}
}
}
return dis[n] <= k;
}
//
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int flag = 0, l, r, mid;
cin >> n >> m >> k;//n个电线杆,m条电话线,k条免费的电话线.
for (int i = 1, x, y, val; i <= m; i++) {
cin >> x >> y >> val;//x,y电线之间的费用val
add(x, y, val); add(y, x, val);//无向边
mx = max(mx, val);//找到最大费用
}
l = 0, r = mx;
while (l < r) {//二分费用,大于mid的费用的线段免费,查找免费数个数,如果大于k则增大mid,如果小于k则左边二分,mid减小
mid = l + ((r - l) >> 2);
if (dijkstra(1, mid, k)) {
r = mid;
flag = 1;
}
else {
l = mid + 1;
}
}
if (flag == 1)
cout << l;
else
cout << "-1";
return 0;
}