[洛谷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
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7812815.html