题目传送门:https://www.luogu.org/problemnew/show/P1462
题意:
有n个点,m条边,某人的血量为k,每一个点会收取对应的价值,而这个人走每一条边也会扣除血,求他能安全走到终点所经过城市中被收取费用最多的城市所收取的费用为多少。
思路:
二分价值x,每一次将得到的价值小于x的去类似于建边(标记一下是否可以选这条边),再跑spfa看看血量是否满足要求即可。
(比较容易,不细讲了)
代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define LL long long
using namespace std;
queue<int> f;
int n,m,k,len=0;
int p[100000],last[100000];
struct node{int x,y,z,next;} a[200000];
int ans=-1;
LL dis[100000];
bool bz[100000],flag[100000];
void ins(int x,int y,int z)
{
a[++len].x=x;a[len].y=y;a[len].z=z;a[len].next=last[x];last[x]=len;
}
LL spfa(LL x)
{
for(int i=1;i<=n;i++)
flag[i]=(p[i]<=x);
if(!flag[1]||!flag[n]) return k+1;
memset(bz,true,sizeof(bz));
memset(dis,127,sizeof(dis));
dis[1]=0;
f.push(1);
while(!f.empty())
{
int x=f.front();
bz[x]=true;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(!flag[y]) continue;
if(dis[x]+a[i].z<dis[y])
{
dis[y]=dis[x]+a[i].z;
if(bz[y])
{
bz[y]=false;
f.push(y);
}
}
}
f.pop();
}
return dis[n];
}
bool pd(LL x)
{
return spfa(x)<=k;
}
int main()
{
int x,y,z,l=1,r=0,mid;
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
r=max(r,p[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&z);
ins(x,y,z);
ins(y,x,z);
}
while(l<=r)
{
mid=(l+r)>>1;
if(pd(mid)) r=mid-1,ans=mid; else l=mid+1;
}
if(ans==-1) printf("AFK"); else printf("%d",ans);
}