P1462 通往奥格瑞玛的道路

题目背景

在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量

有一天他醒来后发现自己居然到了联盟的主城暴风城

在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛

题目描述

在艾泽拉斯,有n个城市。编号为1,2,3,...,n。

城市之间有m条双向的公路,连接着两个城市,从某个城市到另一个城市,会遭到联盟的攻击,进而损失一定的血量。

每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。

假设1为暴风城,n为奥格瑞玛,而他的血量最多为b,出发时他的血量是满的。

歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。


#include<bits/stdc++.h>
using namespace std;
#define maxn 10010
#define maxm 50010
#define maxb 1000000000
#define maxc 1000000000
#define maxf 1000000000

struct Edge{
	int next;
	int to;
	int w;
}edge[2*maxm];
int head[maxn];
int t=0;
void addEdge(int u,int v,int c){
	t++;
	edge[t].to=v;
	edge[t].w=c;
	edge[t].next=head[u];
	head[u]=t;
}

int n,m,b,f[maxn];
int vis[maxn]={0};
int d[maxn];

priority_queue< pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> >  > q;//定义小根堆。 

int Dijkstra(int x){
	if(x<f[1]||x<f[n]) return 0;//1、n 花费大于总花费,则不可能 
	for(int i=1;i<=n;i++) { d[i]=maxc;}
	memset(vis,0,sizeof(vis));
	d[1]=0;
	q.push( make_pair(0,1) );
	
	while(!q.empty()){
		int p=q.top().second;
		q.pop();
		if(vis[p]) continue;
		vis[p]=1;
		int s=head[p];
		while(s){
			if(f[edge[s].to]<=x&&vis[edge[s].to]==0&&d[edge[s].to]>d[p]+edge[s].w){
				d[edge[s].to]=d[p]+edge[s].w;
				q.push( make_pair(d[edge[s].to],edge[s].to) );
			}
			s=edge[s].next;
		}
	}
	if(d[n]<b) return 1;
	return 0;
}
int main(){
	std::ios::sync_with_stdio(false);
	
	cin>>n>>m>>b;
	for(int i=1;i<=n;i++){ cin>>f[i]; }
	int u,v,c;
	for(int i=0;i<m;i++){ 
	    cin>>u>>v>>c;
	    addEdge(u,v,c);
	    addEdge(v,u,c);
	}
	
	if(Dijkstra(maxf)==0){//最大花费过不了 
        cout<<"AFK"<<endl;
        return 0;
    } 
    
	int l=1,r=maxf;
	while(l<=r){//二分查找最小花费
		mid=(l+r)>>1;
		if(Dijkstra(mid)) r=mid-1;
		else  l=mid+1;
	}
	cout<<l<<endl;
	return 0;
}