P1462 通往奥格瑞玛的道路

基本思想:dij+二分
从题干给出的信息中我们可以看出,这个题好像有两个限制,那么是不是要对一维dij进行改进呢?
不需要
仔细分析我们会发现, 输入中,对于两个限制的输入方式是不一样的
这就提示我们是不是可以以一个限制为中心跑最短路,之后二分判断当另一个限制符合要求时,最短路符不符合要求
容易发现这个题应该以bloom为中心跑最短路,判断weight是不是符合条件
代码:

#include<bits/stdc++.h>
#define maxn 100010
using namespace std;


struct node{
	int x,w;
	node(int a=0,int b=0){
		x=a;
		w=b;
	}
};
vector<pair<int,int> > v[maxn];
priority_queue<node> q;
int n,m,bloom;
int b[maxn],c[maxn];
int d[maxn];
bool vis[maxn];

bool operator < (const node &a,const node &b){
	return a.w >b.w ;
}
void add(int a,int b,int c){
	v[a].push_back(make_pair(b,c));
}
bool check(int x){
	if(x<b[1]||x<b[n]) return false;
	//如果发现当前的值已经比端点值还小,说明不可能还有比他小的,返回false
	memset(d,0x3f,sizeof(d)); 
	for(int i=1;i<=n;i++){
		if(b[i]>x) vis[i]=true;//如果当前节点的值已经比x大,说明这个节点没用,跳过不访问
		else vis[i]=false;
	}
	
	d[1]=0;q.push(node(1,0));
	while(!q.empty())
	{
		int s=q.top().x;
		q.pop();
		if(vis[s]) continue;
		vis[s]=1;
		for(int i=0;i<v[s].size();i++){
			int y=v[s][i].first;
			int w=v[s][i].second;
			if(d[y]>d[s]+w)
			{
				d[y]=d[s]+w;
				q.push(node(y,d[y]));
			}
		}
	}
	
	if(d[n]<=bloom) return true;
	return false;
} 



int main(){
	cin>>n>>m>>bloom;
	for(int i=1;i<=n;i++) 
	{
		cin>>b[i];c[i]=b[i];
	}
	
	for(int i=1;i<=m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		add(x,y,z);
		add(y,x,z);
	}
	
	sort(c+1,c+1+n);
	
	int l=1,r=n,mid;
	if((!check(c[n]))){
		cout<<"AFK"<<'
';
		return 0;
	}//check的同时跑了一遍dij 
	
	int ans=c[n];//初始化最多交费
	
	while(l<=r){
		mid=(l+r)>>1;
		if(check(c[mid]))//再跑一遍最大值
		//为c[mid]的时候,判断一下是不是可以更新最大值
		{
			ans=c[mid];
			r=mid-1; 
		}
		else l=mid+1;
	} 
	//为什么这样做是正确的?
	//因为我们先对花费进行了排序,只要我们在当前节点花费的更少,就有更多选择,
	//故决策带有单调性,从而可以二分路费 
	
	cout<<ans<<'
';
	return 0;
	 
	
	
}
原文地址:https://www.cnblogs.com/yxr001002/p/14583311.html