基本思想: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;
}