P1462 通往奥格瑞玛的道路
题目背景
在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量
有一天他醒来后发现自己居然到了联盟的主城暴风城
在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛
题目描述
在艾泽拉斯,有n个城市。编号为1,2,3,...,n。
城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入输出格式
输入格式:
第一行3个正整数,n,m,b。分别表示有n个城市,m条公路,歪嘴哦的血量为b。
接下来有n行,每行1个正整数,fi。表示经过城市i,需要交费fi元。
再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n)。表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,会损失ci的血量。
输出格式:
仅一个整数,表示歪嘴哦交费最多的一次的最小值。
如果他无法到达奥格瑞玛,输出AFK。
输入输出样例
说明
对于60%的数据,满足n≤200,m≤10000,b≤200
对于100%的数据,满足n≤10000,m≤50000,b≤1000000000
对于100%的数据,满足ci≤1000000000,fi≤1000000000,可能有两条边连接着相同的城市。
一道非常有意思的题目啊
没有好好学二分的我并没有一下子看出来这是一题二分
实际上
首先,看见这个问题,就应该想到二分。
所有类似于“求解所有的最 x 值中的最 x 值”的问题,都应该先想一想用二分答案的方法来写。
因为二分是一个猜答案的过程。而且快啊 快啊 log啊
那么核心算法 单源最短路+二分
这是一个土豪,不怕收费。并且我们二分的答案是收的钱。
不断二分答案,不满足的情况有三种:
1 血不够了
2 最多一次费用超过了我们不断通过二分进行缩小的那个ans(最小值)
3走不到(等同于2??)
所以我们在找最短路的过程中 在熟悉的(a+b<c)中 要加上(w[a~b]<=mid)这样的判断。
同时不要忘了d[n]<=b。
至于其他,单源最短路就按照模板的打,二分答案就按照模板的打。找一次,judge一次是否满足情况。
有个技巧。如果mid是INF时就满足不了(你再有钱也不行)就可以直接“-1”了。
#include <cstdio> #include <iostream> #include <cstring> #include <queue> #define MN 6666666 #define INF 9999999999 #define ll long long using namespace std; ll h[MN],to[MN],next[MN],val[MN],cnt; inline void add(ll u,ll v,ll w){ to[++cnt]=v, val[cnt]=w, next[cnt]=h[u], h[u]=cnt; } ll d[MN],w[MN],n,m,b; bool vis[MN]; inline bool spfa(int limit){ memset(vis,0,sizeof vis); for(int i=1;i<=n;i++) d[i]=INF; queue<int> q; d[1]=0,vis[1]=true,q.push(1); while(!q.empty()){ int u=q.front(); q.pop(),vis[u]=false; for(int e=h[u];e;e=next[e]){ if(w[to[e]]<=limit&&d[to[e]]>d[u]+val[e]){ d[to[e]]=d[u]+val[e]; if(!vis[to[e]])vis[to[e]]=true, q.push(to[e]); } } } } int main(){ ll l=0,r=0,mid; cin>>n>>m>>b; for(int i=1;i<=n;i++) cin>>w[i],r=max(r,w[i]); l=max(w[1],w[n]); for(ll i=1,u,v,w;i<=m;i++) cin>>u>>v>>w, add(u,v,w), add(v,u,w); spfa(r); if(d[n]==INF||d[n]>b) { printf("AFK"); return 0; } while(l<=r) spfa(mid=(l+r)>>1)&&d[n]>b ? l=mid+1 : r=mid-1 ; printf("%d",l); return 0; }
暴力压行好像会变慢啊。。