题目描述
在郊区有 $N$ 座通信基站,$P$ 条 双向 电缆,第 $i$ 条电缆连接基站 $A_i$ 和 $B_i$。
特别地,$1$ 号基站是通信公司的总站,$N$ 号基站位于一座农场中。
现在,农场主希望对通信线路进行升级,其中升级第 $i$ 条电缆需要花费 $L_i$。
电话公司正在举行优惠活动。
农产主可以指定一条从 $1$ 号基站到 $N$ 号基站的路径,并指定路径上不超过 $K$ 条电缆,由电话公司免费提供升级服务。
农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。
求至少用多少钱可以完成升级。
样例输入
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
算法:二分+Dijkstra
- 二分就很显然了,因为最终答案是价格最贵的那条电缆,所以我们可以二分最大值,如果当前的最大值小的话(也就是在 $1$ 到 $N$ 的路径中,即使免费升级了 $K$ 条线缆后也仍然到不了 $N$)那么我们就往更大的搜,满足单调性。
- 在升级电缆时,我们最好是把贵的扔给电话公司,便宜的自己来升级,所以我们以当前电缆的费用是否超过最大值为权值,跑一边 Dijkstra,看看最终结果有没有超过 $K$,如果超过 $K$,说明这个“最大值”太小了,我们要往更大的搜,否则,这个“最大值”可行,然后在看一下比这个最大值小的“最大值”行不行。
参考代码
#include <bits/stdc++.h>
#define RI register int
#define rep(x, y, z) for (RI x = y; x <= z; ++x)
#define per(x, y, z) for (RI x = y; x >= z; --x)
using namespace std;
// #define DEBUG 1 //调试开关
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
char buf[MAXSIZE], *p1, *p2;
char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
IO() : p1(buf), p2(buf), pp(pbuf) {}
~IO() { fwrite(pbuf, 1, pp - pbuf, stdout); }
#endif
inline char gc() {
#if DEBUG //调试,可显示字符
return getchar();
#endif
if (p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
return p1 == p2 ? ' ' : *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
template <class T>
inline void read(T &x) {
register double tmp = 1;
register bool sign = 0;
x = 0;
register char ch = gc();
for (; !isdigit(ch); ch = gc())
if (ch == '-') sign = 1;
for (; isdigit(ch); ch = gc()) x = x * 10 + (ch - '0');
if (ch == '.')
for (ch = gc(); isdigit(ch); ch = gc())
tmp /= 10.0, x += tmp * (ch - '0');
if (sign) x = -x;
}
inline void read(char *s) {
register char ch = gc();
for (; blank(ch); ch = gc())
;
for (; !blank(ch); ch = gc()) *s++ = ch;
*s = 0;
}
inline void read(char &c) {
for (c = gc(); blank(c); c = gc())
;
}
inline void push(const char &c) {
#if DEBUG //调试,可显示字符
putchar(c);
#else
if (pp - pbuf == MAXSIZE) fwrite(pbuf, 1, MAXSIZE, stdout), pp = pbuf;
*pp++ = c;
#endif
}
template <class T>
inline void write(T x) {
if (x < 0) x = -x, push('-'); // 负数输出
static T sta[35];
T top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) push(sta[--top] + '0');
}
template <class T>
inline void write(T x, char lastChar) {
write(x), push(lastChar);
}
} io;
const int N = 10001;
int n, p, k;
struct Edge {
int to, nxt, val;
} edge[N << 1];
int head[N], tot;
int vis[N], dis[N];
inline void add(int x, int y, int z) {
++tot;
edge[tot].nxt = head[x];
head[x] = tot;
edge[tot].to = y;
edge[tot].val = z;
}
inline bool dijkstra(int Max) {
priority_queue<pair<int, int> > Q;
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[1] = 0;
Q.push(make_pair(0, 1));
while (!Q.empty()) {
int x = Q.top().second;
Q.pop();
if (vis[x])
continue ;
vis[x] = 1;
for (RI i = head[x]; i; i = edge[i].nxt) {
int y = edge[i].to, val = edge[i].val;
if (dis[y] > dis[x] + (val > Max)) {
dis[y] = dis[x] + (val > Max);
Q.push(make_pair(-dis[y], y));
}
}
}
if (dis[n] > k)
return false;
return true;
}
int main() {
io.read(n), io.read(p), io.read(k);
rep(i, 1, p) {
int x, y, z;
io.read(x), io.read(y), io.read(z);
add(x, y, z);
add(y, x, z);
}
int l = 0, r = 1000001;
while (l < r) {
int mid = (l + r) >> 1;
if (dijkstra(mid))
r = mid;
else
l = mid + 1;
}
if (r == 1000001)
io.write(-1, '\n');
else
io.write(r, '\n');
return 0;
}
orz