P1462 通往奥格瑞玛的道路 (二分+最短路)
题目
P1462 通往奥格瑞玛的道路
给定\(n\)个点\(m\)条边,每个点上都有点权\(f[i]\),每条边上有边权,找一条道路,使边权和小于给定的数\(b\),并使最大点权最小。
解析
二分一下钱,然后跑最短路,判断一下如果只有这么多钱的话能不能到终点(最短路边权和是不是不超过\(b\)),套个最短路板子,套个二分板子,没了。
代码
//二分+最短路
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n, m, b, num;
int l, r, mid = INF;
int dis[N], head[N], f[N];
bool vis[N];
class edge {
public :
int v, nx, w;
}e[N];
class node {
public:
int id, dis;
bool operator < (const node &oth) const {
return this->dis > oth.dis;
}
};
template<class T>inline void read(T &x) {
x = 0; int f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
x = f ? -x : x;
return;
}
inline void add(int u, int v, int w) {
e[++num].nx = head[u], e[num].v = v, e[num].w = w, head[u] = num;
}
priority_queue<node>q;
bool dijkstra() {
memset(dis, INF, sizeof dis);
memset(vis, 0, sizeof vis);
dis[1] = 0;
q.push((node){1, 0}) ;
while (!q.empty()) {
node d = q.top(); q.pop();
int u = d.id;
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; ~i; i = e[i].nx) {
int v = e[i].v;
if (dis[u] + e[i].w < dis[v] && f[v] <= mid) {
dis[v] = dis[u] + e[i].w;
q.push((node){v, dis[v]});
}
}
}
return (dis[n] > b);
}
int main() {
memset(head, -1, sizeof (head));
read(n), read(m), read(b);
for (int i = 1; i <= n; ++i) read(f[i]), r = max(r, f[i]);
for (int i = 1, x, y, z; i <= m; ++i) {
read(x), read(y), read(z);
add(x, y, z), add(y, x, z);
}
if (dijkstra()) {
printf("AFK\n");
return 0;
}
while (l <= r) {
mid = (l + r) >> 1;
if (dijkstra()) l = mid + 1;
else r = mid - 1;
}
printf("%d\n", l);
return 0;
}
如果哪里有错误或不易理解,还请不吝赐教