题目要求是假如有多条路线,求出每条路线的最大值然后选出其中的最小值。
一般这种问法都是二分。
对于单次最大收费小于等于x的情形如果存在方案,那么大于x的也存在方案,因为费用越大所能走的路就越多。显然可以用二分。
然后有两个变量血量以及费用我们以谁为二分的分界点呢??
首先我们可以看到题目输入的边是血量,所以我们可以以经过一条路的血量总和check(mid)不超过题目输入的blood为分界点。若check(mid) <= blood则扩大费用即r = mid,否则缩小费用l = mid + 1;
然后我们确定一下二分的起始点,因为起点和终点是包括费用的,所以费用的最小值为起点和终点中的最大值,而费用的最大值即为每个点费用的最大值
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #define x first #define y second using namespace std; typedef pair<long, int> PLI;//会爆int const int N = 10010, M = 1000010; int l, r; bool st[N]; int fees[N]; int n, m, blood; long long dist[N]; int h[N], e[M], ne[M], w[M], idx; void add(int a, int b, int c)//邻接表 { e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx; idx ++ ; } int check(int maxd)//dijkstra模板 { memset(st, 0, sizeof st); memset(dist, 0x3f, sizeof dist); priority_queue<PLI, vector<PLI>, greater<PLI>> heap; dist[1] = 0; heap.push({dist[1], 1}); while (heap.size()) { auto t = heap.top(); heap.pop(); int ver = t.y; if (st[ver]) continue; st[ver] = true; if (ver == n) return dist[n]; for (int i = h[ver]; i != -1; i = ne[i]) { int j = e[i]; if (fees[j] > maxd) continue;//将大于mid的费用舍去 if (dist[j] > dist[ver] + w[i]) { dist[j] = dist[ver] + w[i]; heap.push({dist[j], j}); } } } return dist[n];//得到从1 - n的所需的血量总和 } int main() { cin >> n >> m >> blood; for (int i = 1; i <= n; i ++ ) { cin >> fees[i]; r = max(r, fees[i]);//二分最大值 } l = max(l, max(fees[1], fees[n]));//二分最小值 memset(h, -1, sizeof h); while (m -- ) { int a, b, c; scanf("%d %d %d", &a, &b, &c); add(a, b, c), add(b, a, c); } while (l < r) { int mid = l + r >> 1; if (check(mid) <= blood) r = mid; else l = mid + 1; } if (check(l) > blood) puts("AFK");//最后找出的答案大于blood说明无解 else printf("%lld\n", r); return 0; }