摘要:简单来讲就是在无向图上求出一条从1到N的路径,使路径上第K+1大的边权尽量小。
第K大的尽量小,这种表述就容易让人想到二分。
蓝书上的解释:因为支付的钱更多时,合法的升级方案一定有包含子花费更少的升级方案,所以答案具有单调性。
那么我们只要把权值大于mid的路径权值设为1,小于mid的置为0,求1到n的最短路是否不超过n即可。
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
typedef pair<LL, int> PII;
const int N = 2e4 + 5, mod = 1e9 + 9, INF = 0x3f3f3f3f;
int e[N], h[N], ne[N], w[N], d[N];
int n, p, k, idx, ans;
bool vis[N];
priority_queue< PII, vector<PII>, greater<PII> > q;
void init() {
memset(h, -1, sizeof h);
memset(d, 0x3f, sizeof d);
memset(vis, false, sizeof vis);
}
void add(int a, int b, int c) {
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
return ;
}
int dij(int mid) {
memset(d, 0x3f, sizeof d);
memset(vis, false, sizeof vis);
d[1] = 0;
q.push(make_pair(0, 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
else vis[x] = 1;
for (int i = h[x]; i != -1; i = ne[i]) {
int y = e[i], z = w[i];
if (z > mid) z = 1;
else z = 0;
if (d[x] + z < d[y]) {
d[y] = d[x] + z;
q.push(make_pair(d[y], y));
}
}
}
return d[n];
}
int main()
{
init();
cin >> n >> p >> k;
int ed = -INF;
while (p--) {
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
add(y, x, z);
ed = max(ed, z);
}
if(dij(0) == INF) {
printf("-1\n");
} else {
int ll = 0, rr = ed;
int mid;
while (ll <= rr) {
// cout << rr << endl;
int mid = (ll + rr) / 2;
if (dij(mid) <= k) {
ans = mid;
rr = mid - 1;
} else {
ll = mid + 1;
}
}
cout << ans << endl;
}
}
本文介绍了一种使用二分法解决特定图论问题的算法,即在无向图中找到从节点1到节点N的路径,使得路径上第K+1大的边权尽可能小。通过调整边权并应用Dijkstra算法,实现对问题的有效求解。
1012

被折叠的 条评论
为什么被折叠?



