[洛谷P1462]通往奥格瑞玛的道路
题目大意:有n个城市,一个人要从1到n。每个城市有一个过路费,经过要付钱(起点终点也要)。城市间有道路连接,每条道路经过时会扣一些血。初始时有b点血。现在问你在能使血量不小于0到达终点时,所经过所有的城市中,收取过路费最大的城市收取过路费的最小值。
解题思路:本题是最小化最大值问题,可用二分答案。
判断答案时,SPFA跑一遍最短路,边权为扣的血量。
做SPFA时,不能经过收费大于当前的答案的点。
最后如果到n的距离(扣的血量)不超过初始血量b,则可行。
C++ Code:
#include<cstdio> #include<cctype> #include<cstring> #include<queue> #define ll long long int n,m,blood,money[10005],head[10005]; ll d[10005]; bool vis[10005]; std::queue<int>q; struct edge{ int to;ll dis;int nxt; }e[100050]; inline int max(int a,int b){return a>b?a:b;} inline int readint(){ char c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } bool ok(int mid){ memset(d,0x3f,sizeof d); memset(vis,0,sizeof vis); d[1]=0; vis[1]=true; q.push(1); while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for(int i=head[u];i;i=e[i].nxt) if(money[e[i].to]<=mid&&d[e[i].to]>d[u]+e[i].dis){ d[e[i].to]=d[u]+e[i].dis; if(!vis[e[i].to]){ vis[e[i].to]=true; q.push(e[i].to); } } } return d[n]<=blood; } int main(){ n=readint(); m=readint(); blood=readint(); memset(head,0,sizeof head); int l,r=0; for(int i=1;i<=n;++i)r=max(r,money[i]=readint()); l=max(money[1],money[n]); for(int cnt=0;m--;){ int u=readint(),v=readint(),t=readint(); e[++cnt]=(edge){v,t,head[u]}; head[u]=cnt; e[++cnt]=(edge){u,t,head[v]}; head[v]=cnt; } int ans=-11111; while(l<=r){ int mid=(l+r)>>1; if(ok(mid))r=(ans=mid)-1;else l=mid+1; } if(ans==-11111)puts("AFK");else printf("%d\n",ans); return 0; }