洛谷 P1462 通往奥格瑞玛的道路

题目传送门

题面里有最大值最小,所以直接想到二分答案.在检验答案时,如果dfs爆搜,会得46分.

对于题目中的两个限制:金钱和血量.金钱我们可以二分答案处理,而血量我们希望消耗的越少越好,最短路.最后和0比较看能不能活着到终点.

这道题不卡spfa.

46分代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;

int n,m,b,tot,head[10001];
long long a[10001],sum,num = 999999999999,ans,dis[10001];
bool flag,vis[10001];
struct kkk {
	int to,next;
	long long len;
}e[100001];

inline void add(int x,int y,int z) {
	e[++tot].to = y;
	e[tot].next = head[x];
	e[tot].len = z;
	head[x] = tot;
}

inline bool dp(int mid,int rt,int bl) {
	queue<int> q;
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	dis[rt] = 0;
	q.push(rt);
	vis[rt] = 1;
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		vis[u] = 0;
		for(int i = head[u];i; i = e[i].next) {
			int o = e[i].to;
			if(a[o] > mid) continue;
			if(dis[o] > dis[u] + e[i].len) {
				dis[o] = dis[u] + e[i].len;
				if(!vis[o]) {
					vis[o] = 1;
					q.push(o);
				}
			}
		}
	}
	if(dis[n] < bl) return 1;
	return 0;
}

int main() {
	scanf("%d%d%d",&n,&m,&b);
	for(int i = 1;i <= n; i++) {
		scanf("%lld",&a[i]);
		sum = max(sum,a[i]);
		num = min(num,a[i]);
	}
	for(int i = 1;i <= m; i++) {
		int x,y;
		long long z;
		scanf("%d%d%lld",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	long long l = num,r = sum,mid;
	while(l <= r) {
		memset(vis,0,sizeof(vis));
		mid = l + r >> 1;
		flag = 0;
		if(dp(mid,1,b))
			r = mid - 1;
		else 
			l = mid + 1;
	}
	if(l <= sum)
		printf("%lld",l);
	else printf("AFK");
	return 0;
}
原文地址:https://www.cnblogs.com/lipeiyi520/p/13875892.html