【洛谷习题】通往奥格瑞玛的道路
题目的描述就很有意思,可以顺便去了解一下魔兽的背景故事。学习使我们快乐!
题目链接:https://www.luogu.org/problemnew/show/P1462
大清早上起来A掉一道题,好兴奋。看到题目要求收费最多的一次的最小值,想到用二分答案,二分这个最小值,然后去跑最短路,看是否可以,再不断更新区间,使这个值尽量小。几乎没有什么难点,但需要注意的细节有几个。估计答案的最大值应为收费最多的城市所收的费用;检验时,我是采用若发现某个结点的收费比当前所验证的答案大,则不再扩展,最后通过检查是否存在最短路,最短路是否可以回到奥格瑞玛,但问题是,如果终点不符合要求,同样会存在最短路,最短路可能也可以回到奥格瑞玛,所以还需要额外检查终点是否不超过检验的答案。
还有,无向图用邻接表存储时,每条边会存两次!!!
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 5 using namespace std; 6 7 inline int get_num() { 8 int num = 0; 9 char c = getchar(); 10 while (c < '0' || c > '9') c = getchar(); 11 while (c >= '0' && c <= '9') 12 num = num * 10 + c - '0', c = getchar(); 13 return num; 14 } 15 16 const int maxn = 1e4 + 5, maxm = 5e4 + 5, inf = 0x3f3f3f3f; 17 18 int head[maxn], eid; 19 20 struct Edge { 21 int v, w, next; 22 } edge[2 * maxm]; 23 24 inline void insert(int u, int v, int w) { 25 edge[++eid].v = v; 26 edge[eid].w = w; 27 edge[eid].next = head[u]; 28 head[u] = eid; 29 } 30 31 struct node { 32 int id, dist; 33 node(int i, int d) : id(i), dist(d) {} 34 bool operator < (const node& rhs) const { 35 return dist > rhs.dist; 36 } 37 }; 38 39 int n, m, b, f[maxn], dist[maxn], vis[maxn]; 40 41 priority_queue<node> q; 42 43 inline int check(int x) { 44 memset(vis, 0, sizeof(vis)); 45 memset(dist, inf, sizeof(dist)); 46 dist[1] = 0; 47 q.push(node(1, 0)); 48 while (!q.empty()) { 49 int u = q.top().id; 50 q.pop(); 51 if (vis[u]) continue; 52 vis[u] = 1; 53 for (int p = head[u]; p; p = edge[p].next) { 54 int v = edge[p].v, w = edge[p].w; 55 if (f[v] > x) continue; 56 if (dist[v] > dist[u] + w) { 57 dist[v] = dist[u] + w; 58 q.push(node(v, dist[v])); 59 } 60 } 61 } 62 if (dist[n] > b) return 0; 63 else return 1; 64 } 65 66 int main() { 67 n = get_num(), m = get_num(), b = get_num(); 68 int mf = 0; 69 for (int i = 1; i <= n; ++i) { 70 f[i] = get_num(); 71 if (f[i] > mf) mf = f[i]; 72 } 73 for (int i = 1; i <= m; ++i) { 74 int u = get_num(), v = get_num(), w = get_num(); 75 insert(u, v, w); 76 insert(v, u, w); 77 } 78 if (!check(mf)) {printf("AFK"); return 0;} 79 int l = 1, r = mf; 80 while (l < r) { 81 int mid = l + (r - l) / 2; 82 if (check(mid)) r = mid; 83 else l = mid + 1; 84 } 85 printf("%d", l); 86 return 0; 87 }