【 luogu P1462 】 通往奥格瑞玛的道路【 二分 + Spfa 】

luogu传送门

读题读了好久,,,

有 n 个点, m 条双向边 ,每个点有权值 fi ,每条边有权值 ci 。 总能量值为 b , 经过边时 将会消耗 能量值。

要求:成功从 1 号点到达 n 号点(到达时 能量值 >=0)  求 使 中途经过的 最大的点权 最小 ,输出此值

注明 来源 :luogu 题解区 (非本人)

【 题目解析 】

最大点权最小 -> 二分

二分 + Spfa 检验

因为 最后 要求输出 最小的 点权 ,因此我们 二分 点权(注意边界)

judge 的时候,关于 u 的松弛操作: v 点要满足 f_{v} <=  当前二分的点权才松弛

                          最后判断 这样走下来的 到 n 的最短路 长度是否小于 b

 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define LL long long
#define inf 0x7f7f7f7f
#define inff 0x7f7f7f7f7f7f7f7f
using namespace std;

inline int wread(){
	char c(getchar ());int wans(0),flag(1);
	while (c<'0' || c>'9'){if (c=='-') flag=-1; c=getchar ();}
	while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
	return wans*=flag;
}

inline LL ll_wread(){
	char c(getchar ());LL wans(0),flag(1);
	while (c<'0' || c>'9'){if (c=='-') flag=-1; c=getchar ();}
	while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
	return wans*=flag;
}

int n,m;
LL b,f[10005];
int K,hed[10005];
struct node{int v,nxt;LL w;}e[100005];
void ad (int u,int v,LL w){e[++K].v=v;e[K].w=w;e[K].nxt=hed[u];hed[u]=K;}
int que[100005],h,t;
LL dis[10005];
bool ins[10005];
bool jud (LL mon){// dian
	if (f[1]>mon || f[n]>mon )	return false;
	memset (ins,false,sizeof ins);
	for (int i(1);i<=n;++i)
		dis[i]=inff;
	h=0,t=0;
	que[++h]=1;
	dis[1]=0;
	ins[1]=true;
	while (t<h){
		int x(que[++t]);ins[x]=false;
		for (int i(hed[x]);i!=-1;i=e[i].nxt){
			int v(e[i].v);
			if ( dis[v] > dis[x] + e[i].w  &&  f[v]<=mon )	dis[v] = dis[x] + e[i].w;
			else continue;
			if (!ins[v])	que[++h]=v;
		}
	}
	
	if (dis[n] <= b)	return true;
	return false;	
}
int main (){
	
	memset (hed,-1,sizeof hed);
	LL l=inff,r=-inff;LL min_a,max_a;
	n=wread();m=wread();b=ll_wread();
	for (int i(1);i<=n;++i)
		f[i]=ll_wread(),l=min(l,f[i]), r=max(r,f[i]);
	for (int i(1);i<=m;++i){
		int u(wread()),v(wread());LL w(ll_wread());
		ad (u,v,w);ad (v,u,w);
	}
	LL ans=inff;
	min_a=l;max_a=r;
	r++;
	l--;
	while (l<r){
		LL mid((l+r)/2);//hua fei
		if (mid>max_a)	r=mid;
		else if (mid<min_a)	l=mid+1;
		else {
			if (jud(mid))	r=mid,ans=min (ans,mid);
			else l=mid+1;
		}
	}
	if (ans==inff)	puts("AFK");
	else printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/violinlove/article/details/81433619
今日推荐