通往奥格瑞玛的道路——dijkstra+二分

P1462 通往奥格瑞玛的道路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

一道将dijkstra和二分完美结合的一道题。

分析题意:

1.题中的“他所经过的所有城市中最多的一次收取的费用的最小值是多少”,太绕了。意思就是说这个人经过的所有城市中收费最大的那个城市的费用最少是多少。举个例子,假如这个人有两条满足条件的路可以走,第一条路收费最多的那个城市需要的费用是10块钱,第二条路收费最多的那个城市需要的费用是18块钱,那么答案就是10块钱。注意:题中这句话可以转化为求最大值的最小值,那么就是二分二分二分!所以我们求最后答案需要用二分解决。

 

2.题中有个必须要满足的条件,血量不能是负数,可以将血量当作dijkstra的dist距离,如果跑一遍图最后dist[n]大于总血量,那么说明这个人gg了,跑不到终点。

 

3.二分的判断条件是在单个城市最大收费是mid的情况下 是否能跑完整个图。

所以dijkstra是bool类型,并且在dijkstra中if判断血量(距离)的时候要同时判断这个城市的收费是否小于等于mid

 

收获:

真正明白了二分中if判断条件的意义,格局稍微打开了点,会将dijkstra与二分联系在一起了。并且明白了最大值的最小值这种关键句,是二分的意思。

 

代码实现:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int sum=0;char a=getchar();
 6     while(a<'0'||a>'9')a=getchar();
 7     while(a>='0'&&a<='9')
 8     {
 9         sum=(sum<<3)+(sum<<1)+a-'0';
10         a=getchar();
11     }
12     return sum;
13 }
14 const int N=1e4+100,M=1e5+100,maxx=1e9+5;
15 int n,m,b,idx;
16 int f[N],dist[N],h[N];
17 bool st[N];
18 typedef pair<int,int> pii;
19 priority_queue<pii,vector<pii>,greater<pii> >q;
20 
21 struct EDG
22 {
23     int ne,to,w;
24 }e[M];
25 
26 void add(int x,int y,int v)
27 {
28     idx++;
29     e[idx].ne=h[x];e[idx].to=y;e[idx].w=v;h[x]=idx;
30 }
31 
32 bool dijkstra(int u)
33 {
34     if(u<f[1])return 0;    //如果费用u连1都进不去,那就没必要继续跑图了 
35     
36     
37     memset(dist,0x3f,sizeof dist);
38     memset(st,0,sizeof st);
39     dist[1]=0;
40     q.push({0,1});
41     
42     while(q.size())
43     {
44         pii sta=q.top();q.pop();
45         int x=sta.second,distance=sta.first;
46         if(st[x])continue;
47         st[x]=1;
48         
49         for(int i=h[x];i;i=e[i].ne)
50         {
51             int y=e[i].to;
52             if(dist[y]>distance+e[i].w&&f[y]<=u)//注意每个地点的费用都小于等于指定的费用     
53             {
54                 dist[y]=distance+e[i].w;
55                 if(!st[y])q.push({dist[y],y});
56             }
57         }
58     }
59     if(dist[n]<=b)return 1;    
60     //如果在每个地点的收费都小于等于u的情况下,能跑完全图就返回1 
61     else return 0;
62     
63 }
64 
65 
66 int main()
67 {
68     n=read();m=read();b=read();
69     for(int i=1;i<=n;i++)f[i]=read();
70     
71     for(int i=1;i<=m;i++)
72     {
73         int a,t,c;
74         a=read();t=read();c=read();
75         add(a,t,c);add(t,a,c);
76     }
77     
78     if(dijkstra(maxx)==0)    //在费用最大的时候仍然不能跑完全图,说明没戏了 
79     {
80         printf("AFK\n");
81         return 0;
82     }
83     
84     int l=1,r=maxx;
85     while(l<=r)
86     {
87         int mid=(l+r)>>1;
88         int c=dijkstra(mid);    
89         //用dijkstra判断,如果在单个收费最多为mid的时候能跑完全图就满足条件 
90         
91         if(c)r=mid-1;    //满足条件,就试一试如果最大值再小一点的情况 
92         else l=mid+1;    //不满足条件,就试试 最大值再大点的情况 
93     }
94     
95     printf("%d\n",l);
96     
97     
98     return 0;
99 }
View Code

 

posted @ 2022-03-05 12:19  wellerency  阅读(31)  评论(0编辑  收藏  举报