洛谷 P1462 通往奥格瑞玛的道路 二分+Dijkstra优先队列优化
代码如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#define MAX 10010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int n,m,b,maxl=-1;//n为顶点数,m为边的数量,b为血量,maxl为可能收取的最大费用
int visit[MAX],dis[MAX];
int money[MAX];//经过某个城市所要收取的费用
struct edge{//存储边
int to;//边的指向
int cost;//边的权值
};
vector<edge> adj[MAX];
typedef pair<int,int> p; //first是最短距离,second是顶点的编号
struct cmp{//优先队列的cmp是一个类
bool operator()(p a,p b) {
return a.first>b.first;
}
};
//priority_queue<p,vector<p>,cmp > q;
bool check(int x){
if(money[1]>x) return false;//如果第一个点就不能走,直接返回false
for(int i=0;i<MAX;i++){
visit[i]=0;
dis[i]=INF;
}
dis[1]=0;
priority_queue<p,vector<p>,cmp > q;
q.push(p(0,1));//将源结点放入优先队列
while(!q.empty()){
p top=q.top();
q.pop();
int u=top.second;
if(visit[u]==0){
visit[u]=1;
for(int i=0;i<adj[u].size();i++){
edge e=adj[u][i];
if(money[e.to]>x) continue;//如果新扩展的点不符合要求,继续寻找
if(dis[e.to]>dis[u]+e.cost){
dis[e.to]=dis[u]+e.cost;
q.push(p(dis[e.to],e.to));
}
if(e.to==n){//如果已经到达了n
if(dis[n]>=b) return false;//说明血量不足
else return true;//说明血量充足
}
}
}
}
return false;
}
int main(){
cin>>n>>m>>b;
for(int i=1;i<=n;i++){
cin>>money[i];
maxl=max(maxl,money[i]);
}
int a,c,len;
for(int i=0;i<m;i++){
cin>>a>>c>>len;
edge e;
e.to=c;
e.cost=len;
adj[a].push_back(e);//adj[a]是从顶点a出发的边的集合
e.to=a;
adj[c].push_back(e);//adj[b]是从顶点b出发的边的集合
}
//二分
int l=1,r=maxl,ans=-1;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)) ans=mid,r=mid-1;//说明mid大了,更新ans
else l=mid+1;
}
if(ans==-1) printf("AFK");//如果每次都没有扩展成功说明不能到达
else printf("%d\n", ans);
return 0;
}