P1462 通往奥格瑞玛的道路

59 阅读2分钟

P1462 通往奥格瑞玛的道路

题目大意

1为起点,n为终点,有一个极限权值b,要求你花费b以内的权值到达终点,每一个点都有价值fi,让你计算在能到达终点的情况下每次经过的所有点中的价值最大点中的最小价值。

分析题目

遇见这种“求最大中的最小”这种情况要能想到是二分答案,既然如此,那就很显然最后要对答案二分,每一次二分如何check呢,那当然就是在最大价值为mid的情况下是否能够到达终点,既然如此每一次都跑一遍dijkstra的时候只要筛掉所有价值大于mid的情况即可,分析到这就可以动手写代码了。其中还有几个注意的点,会在代码中给出注释

//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Os")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("Og")
//#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair <ll , ll> pii;
typedef priority_queue <ll ,vector<ll> ,greater<ll> > xiao;  
typedef priority_queue <ll ,vector<ll> ,less<ll> > da; 
const int N=2e5 + 10,inf = 0x3f3f3f3f;
const ull P = 131;

int a[N];
int h[N],e[N],ne[N],idx,w[N];
int dist[N],dist2[N],dist3[N];
bool st[N];
int n,m,b;
ll maxn = -1,flag = 0;

void add(int u,int v,int c)
{
	e[idx] = v;
	w[idx] = c;
	ne[idx] = h[u];
	h[u] = idx++;
}

void dijkstra(int u)
{
	memset(dist , inf , sizeof dist);
	memset(st , 0 , sizeof st);
	dist[1] = 0;
	priority_queue <pii ,vector<pii> , greater<pii> > heap;
	
	if(a[1] <= u)       //需要对起点特判 ,之后没有对起点的判断 
	{
		heap.push({0 , 1});
	}
	
	while(heap.size())
	{
		auto t = heap.top();
		heap.pop();
		int ver = t.second,distance = t.first;
		
		if(st[ver])
		{
			continue;
		}
		
		st[ver] = 1;
		
		for(int i = h[ver] ; i != -1 ; i = ne[i])
		{
			int j = e[i];
			
			if(a[j] > u)      //与dijkstra模板不同之处,需要筛掉所有价值大于每轮规定的点 
			{
				continue;
			}
			if(dist[j] > distance + w[i])
			{
				dist[j] = distance + w[i];
				heap.push({dist[j] , j});
			}
		}
	}
}

int main()
{
    std::ios::sync_with_stdio(false);
	std::cin.tie(0),cout.tie(0);

	memset(h , -1 , sizeof h);
   	cin>>n>>m>>b;
   
   	for(int i = 1 ; i <= n ; i++)
    {
   		cin>>a[i];
    }
   	
   	while(m--)
    {
   		int u,v,c;
   		cin>>u>>v>>c;
   		add(u , v , c);
   		add(v , u , c);
    }

	int l = 1,r = 1e9;    //二分的范围由数据范围判断 
	while(l < r)
	{
		int mid = (l + r) >> 1;
		dijkstra(mid);     //每次确定完mid后跑一边dijkstra 
		if(dist[n] > b)    //判断条件是到达终点时消耗的权值是否小于等于极限权值 
		{
			l = mid + 1;
		}else
		{
			r = mid;
		}
	}
	
	dijkstra(l);          //跑完二分的时候记得还需要跑一次dijkstra 
	if(dist[n] <= b)
	{
		cout<<l;
	}else
	{
		cout<<"AFK";
	}
}