E - Charles in Charge
本质上是最短路+二分
本题要求是再求最短路的基础上限制边长,边长最长是 \(dis*(1 + x / 100)\),在求出限制边长后,可以通过二分找出答案
在二分中,大于限制边长的不予考虑
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
typedef long long ll;
typedef pair<ll, ll> PII;
int h[N], e[M], w[M], ne[M], idx;
int n, m, x;
bool st[N];
ll dis[N];
const ll INF = 1e18;//最大值
inline void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
ll disjktra(ll l)//限制边长
{
for (int i = 0; i <= n; i++) {
dis[i] = INF;
st[i] = 0;
}
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({ 0, 1 });
dis[1] = 0;
while (heap.size()) {
PII r = heap.top();
heap.pop();
ll dist = r.first;
if (st[r.second])
continue;
st[r.second] = 1;
for (int i = h[r.second]; i != -1; i = ne[i]) {
int j = e[i];
if (w[i] <= l && dis[j] > dist + w[i]) {
dis[j] = dist + w[i];
heap.push({ dis[j], j });
}
}
}
return dis[n];
}
int main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m >> x;
memset(h, -1, sizeof h);
ll v = -1;
while (m--) {
ll a, b, c;
cin >> a >> b >> c;
v = max(v, c);
add(a, b, c);
add(b, a, c);
}
ll u = disjktra(INF);
double sum = u * 1.0 * (x * 1.0 / 100 + 1) * 1.0;
ll l = 0, r = v;
while (l < r) {
ll mid = l + (r - l) / 2;
if (disjktra(mid) * 1.0 == sum) {
{
cout << mid << endl;
return 0;
}
} else if (disjktra(mid) * 1.0 < sum)
r = mid;
else if (disjktra(mid) * 1.0 > sum)
l = mid + 1;
}
cout << l << endl;
return 0;
}