题目链接:https://www.luogu.org/problem/P1462
思路:二分最大金钱数,最短路需要耗费的血量。
直接二分最大金币数,无论该金币数是否出现在图上,通过二分的区间缩小即金币范围缩小,
一定会得到一个图上存在的最小的最大金币数。
最短路耗血量,只需要有一条能满足该最大金币数即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <stack> 7 #include <set> 8 #include <cmath> 9 #include <string> 10 #include <map> 11 #include <cmath> 12 #include <iomanip> 13 using namespace std; 14 15 typedef long long LL; 16 #define inf 1e9 17 #define rep(i,j,k) for(int i = (j); i <= (k); i++) 18 #define rep__(i,j,k) for(int i = (j); i < (k); i++) 19 #define per(i,j,k) for(int i = (j); i >= (k); i--) 20 #define per__(i,j,k) for(int i = (j); i > (k); i--) 21 22 const int N = (int)1e4 + 10; 23 int head[N]; 24 int f[N]; 25 int cnt; 26 bool vis[N]; 27 LL dis[N]; 28 int n,m,tx; 29 int u,v,w; 30 31 struct Edge{ 32 int to; 33 int next; 34 int w; 35 }e[5 * N << 1]; 36 37 struct node{ 38 int loc; 39 int w; 40 41 bool friend operator<(const node& a,const node& b){ 42 return a.w > b.w; 43 } 44 }; 45 priority_queue<node > que; 46 47 void add(int u,int v,int w){ 48 e[cnt].to = v; 49 e[cnt].w = w; 50 e[cnt].next = head[u]; 51 head[u] = cnt++; 52 } 53 54 LL dijkstra(LL mid){ 55 56 while(!que.empty()) que.pop(); 57 rep(i,1,n){ 58 vis[i] = false; 59 dis[i] = inf; 60 } 61 dis[1] = 0; 62 que.push(node{1,0}); 63 64 int u,v,w; 65 while(!que.empty()){ 66 u = que.top().loc; 67 que.pop(); 68 vis[u] = true; 69 70 for(int o = head[u]; ~o; o = e[o].next){ 71 v = e[o].to; 72 w = e[o].w; 73 74 if(f[v] > mid) continue; //超出金币限度 75 76 if(!vis[v] && dis[v] > dis[u] + w){ 77 dis[v] = dis[u] + w; 78 que.push(node{v,dis[v]}); 79 } 80 } 81 } 82 83 return dis[n]; 84 } 85 86 int main(){ 87 88 scanf("%d%d%d",&n,&m,&tx); 89 90 rep(i,1,n) head[i] = -1; 91 cnt = 0; 92 rep(i,1,n) scanf("%d",f + i); 93 rep(i,1,m){ 94 scanf("%d%d%d",&u,&v,&w); 95 add(u,v,w); 96 add(v,u,w); 97 } 98 99 LL l = 1,r = (LL)1e9; 100 LL mid; 101 int ans = inf; 102 bool ok = false; 103 while(l <= r){ 104 mid = (l + r) >> 1; 105 if(dijkstra(mid) > (LL)tx) l = mid + 1; //该mid金币不存在一条路 106 else{//该mid金币存在一条路,继续二分答案 107 ans = min(mid,(LL)ans); //记录可行的mid 108 r = mid - 1; 109 ok = true; 110 } 111 } 112 if(!ok) printf("AFK "); 113 else printf("%d ",ans); 114 115 getchar(); getchar(); 116 return 0; 117 }