P1462 通往奥格瑞玛的道路
题意:给出一个图,让我们从1走到n;
每一条边有一个权值(伤害值),每一个顶点也有一个权值(收费值);
从1走到n的某路径的答案为,这些路径中的最大值; 假如生命耗尽,也无法走到终点,
现在让我们找出这样一条路径,求最小的花费值;
思路:我们通过二分便可以解决;
二分对象为花费值,然后每一次按这个花费值去跑SPFA算出在这花费值的情况下最小的伤害
假如遇到比该花费值大的点,就跳过;
然后该最小伤害大于本身最大生命值的话,则不满足,反之满足
但是,当我们将数据范围定义到题目给出的范围的时候,大致为:(1,1e9)
这样做会超时,然后我们换了一种跑范围的方法,将范围降到了(1,1e4)
很显然,我们枚举的花费值最后的答案,如果满足的话,肯定是等于这些花费值中的其中一个
所以我们只需要跑花费值这个数组就可以了
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e4+10; 4 const int inf=0x3f3f3f3f; 5 int money[maxn]; 6 int n,m,health; 7 int dis[maxn]; 8 int vis[maxn]; 9 int sto[maxn]; 10 struct node 11 { 12 int w,v,nxt; 13 }G[100010]; int head[100010];int num; 14 void add(int u,int v,int w) 15 { 16 G[++num].v=v;G[num].w=w;G[num].nxt=head[u];head[u]=num; 17 } 18 void SPFA(int mid) 19 { 20 if(money[1]>mid) return; 21 queue<int>q; 22 q.push(1); 23 dis[1]=0; 24 vis[1]=1; 25 while(!q.empty()){ 26 int u=q.front(); 27 q.pop(); 28 vis[u]=0; 29 for(int i=head[u];i;i=G[i].nxt){ 30 int v=G[i].v,w=G[i].w; 31 if(money[v]>mid) continue; 32 if(dis[v]>dis[u]+w){ 33 dis[v]=dis[u]+w; 34 if(!vis[v]){ 35 vis[v]=1; 36 q.push(v); 37 } 38 } 39 } 40 } 41 } 42 int check(int mid) 43 { 44 memset(dis,inf,sizeof(dis)); 45 memset(vis,0,sizeof(vis)); 46 SPFA(mid); 47 if(dis[n]<=health) return 1; 48 else return 0; 49 } 50 int main() 51 { 52 scanf("%d%d%d",&n,&m,&health); 53 for(int i=1;i<=n;i++){ 54 scanf("%d",&money[i]); 55 sto[i]=money[i]; 56 } 57 for(int i=1;i<=m;i++){ 58 int u,v,w; 59 scanf("%d%d%d",&u,&v,&w); 60 add(u,v,w); 61 add(v,u,w); 62 } 63 sort(sto+1,sto+1+n); 64 if(check(sto[n])==0){ 65 printf("AFK\n"); 66 return 0; 67 } 68 int L=1,R=n; 69 int ans; 70 while(L<=R){ 71 int mid=L+R>>1; 72 if(check(sto[mid])){ 73 ans=sto[mid]; 74 R=mid-1; 75 } 76 else L=mid+1; 77 } 78 printf("%d\n",ans); 79 return 0; 80 }