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

题目链接: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\n");
113     else printf("%d\n",ans);
114 
115     getchar(); getchar();
116     return 0;
117 }

猜你喜欢

转载自www.cnblogs.com/SSummerZzz/p/11418091.html
今日推荐