luogu#P1462 通往奥格瑞玛的道路

题意:

给出一张有 \(n\) 个点, \(m\) 条边的无向图 ,有 \(b\) 点血量。

每个点上有一个点权 \(f[i]\) ,表示经过这个点需要交 \(f[i]\) 的费用。,每条边上有一个边权 \(C[i]\) ,表示经过这条边需要扣除 \(C[i]\) 的血量

求能从起点 \(1\) 到达 \(n\) 的情况下交费最多一次的最小值

解法:

先判断一次假设血量为最大血量+ 时是否可以走通

然后二分每次交的最大费用 \(w\) ,用dijkstra求从源点到终点需要的最小血量

数据比较大需要开long long

#include<iostream>
#include<queue>
#include<cstring>
#define ll long long
#define M 50005
#define N 10005
using namespace std;
struct Edge{ll next,to,dis;}edge[M<<1];

struct node{ll dis,u;bool operator < (const node &x)const {return x.dis<dis;}};

ll n_e,n,m,head[N],hp,c[N],mxm,dis[N];

bool vis[N];

bool dij(ll s,ll t,ll w);
inline void addedge(ll from,ll to,ll dis);

void init();
int main()
{	
	ll l,r;
	init();
	if(dij(1,n,1000000001)==0)

	{
		cout<<"AFK";
		return 0;
	}
	l=0; r=mxm;
 	while(l<=r)
	{
		int mid=l+r>>1;
		if(dij(1,n,mid))

			r=mid-1;
		else
			l=mid+1;
	}
	cout<<l;
	return 0;
}
bool dij(ll s,ll t,ll w)
{
	if(c[s]>w||c[t]>w)
		return 0;
	memset(dis,0x7f,sizeof(dis));

	memset(vis,0,sizeof(vis));
	priority_queue<node> q;
	dis[s]=0;

	q.push((node){0,s});
	while(!q.empty())
	{
		node tmp=q.top();
		q.pop();
		ll now=tmp.u;
		if(vis[now])
			continue;
		vis[now]=1;
		for(int i=head[now];i;i=edge[i].next)
		{
			int v=edge[i].to;
			if(dis[v]>dis[now]+edge[i].dis)

			{
				dis[v]=dis[now]+edge[i].dis;

				if(!vis[v]&&c[v]<=w)
					q.push((node){dis[v],v});

			}
		}
	}
	if(dis[t]<=hp)

		return 1;
	else	
		return 0;
}

inline void addedge(ll from,ll to,ll dis)

{
	edge[++n_e].next=head[from];
	edge[n_e].to=to;
	edge[n_e].dis=dis;

	head[from]=n_e;
}
void init()
{
	cin>>n>>m>>hp;
	mxm=-1; 
	for(int i=1;i<=n;i++)
	{
		ll w;
		cin>>w;
		mxm=max(mxm,w);
		c[i]=w;
	}
	for(int i=1;i<=m;i++)
	{
		ll u,v,w;
		cin>>u>>v>>w;
		if(u==v)
			continue;
		addedge(u,v,w);

		addedge(v,u,w);

	}
}

posted @ 2019-10-18 19:45  nenT  阅读(127)  评论(0)    收藏  举报