洛谷P1462-通往奥格瑞玛的道路-二分+最短路

洛谷P1462-通往奥格瑞玛的道路

题目描述

在艾泽拉斯,有\(n\)个城市。编号为\(1,2,3,...,n\)

城市之间有\(m\)条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。

每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。

假设\(1\)为暴风城,\(n\)为奥格瑞玛,而他的血量最多为\(b\),出发时他的血量是满的。

歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。


题解:

\(cost[i]\)为第\(i\)个城市的过路费。则在\([min\{cost\},max\{cost\}]\)之间二分一个\(cost\),之后跑\(Dijkstra\)\(cost\)大于\(mid\)的城市不能通行,小于等于\(mid\)的城市可以通行,最后如果\(dis[n]\)小于等于歪嘴哦的总血量\(b\)则这个\(mid\)可行。

如果最后能找到一个可行的\(mid\),那么最小的\(mid\)就是答案,否则就输出\(AFK\)


AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>

typedef long long ll;

const int Maxn = 50005;
const ll INF = 0x3f3f3f3f3f3f3f3f;

struct EDGE {
	int v, next;
	ll w;
} e[Maxn << 1];

struct Node {
	int pos;
	ll dis;

	Node(){}

	Node(int pos, ll dis):pos(pos), dis(dis){}

	bool operator < (const Node &x) const {
		return dis > x.dis;
	}
};

int head[Maxn], tot = 1;
int nv, ne, b;
ll dis[Maxn], cost[Maxn];
bool vis[Maxn];

void add(int u, int v, ll w) {
	e[tot].v = v; 
	e[tot].w = w;
	e[tot].next = head[u];
	head[u] = tot++;
}

bool dij(int top) {
	if (cost[1] > top) {
		return false;
	}
	memset(dis, INF, sizeof dis);
	memset(vis, 0, sizeof vis);
	dis[1] = 0;
	std::priority_queue<Node>q;
	q.push(Node(1, 0));
	for (; !q.empty();) {
		int u = q.top().pos;
		q.pop();
		for (int i = head[u]; i; i = e[i].next) {
			int v = e[i].v;
			int w = e[i].w;
			if (cost[v] <= top && dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				q.push(Node(v, dis[v]));
			}
		}
	}
	return dis[nv] <= b;
}

void solve() {
	scanf("%d %d %d", &nv, &ne, &b);
	ll l = INF, r = -INF;
	for (int i = 1; i <= nv; i++) {
		scanf("%lld", cost + i);
		l = std::min(l, cost[i]);
		r = std::max(r, cost[i]);
	}
	int u, v;
	ll w;
	for (int i = 0; i < ne; i++) {
		scanf("%d %d %lld", &u, &v, &w);
		add(u, v, w);
		add(v, u, w);
	}
	ll ans = -1;
	while (l <= r) {
		int mid = (l + r) >> 1;
		if (dij(mid)) {
			ans = mid;
			r = mid - 1;
		} else {
			l = mid + 1;
		}
	}
	if (ans == -1) {
		printf("AFK\n");
	} else {
		printf("%lld\n", ans);
	}
}

int main() {
	solve();
	return 0;
}

posted @ 2021-02-07 14:45  牟翔宇  阅读(58)  评论(0编辑  收藏  举报