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

本文介绍了如何利用图论中的SPFA算法和二分查找策略来解决一个最大值最小问题。通过先运行Bellman-Ford+SPFA找到起点到终点的可能路径,然后根据血量限制进行二分查找,确定最优解。在每次SPFA迭代中,会删除路径花费超过预设二分值的节点。最后,通过链式前向星结构配合手工排序和二分查找进一步优化解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

移步到新Blog获得更好的代码阅读体验




看了很长时间才看懂这是一个最大值最小问题 果断二分答案。

主要思想是先跑一边Bellman-Ford+队列优化(也叫SPFA)把二分值设定成+∞ 然后看一看如果到终点的花费大于血量就输出AFK(away from keyboard)

如果可行就快排点权+二分下标 如果当前二分值可以跑到终点(跑SPFA判)就向左找(升序sort),不然就向右找。

跑SPFA的时候传一个upat也就是二分值 把点权大于二分值的点都判(删)掉 


还有一点就是最后还要判一下二分值。链式前向星+SPFA+手写Sort没有注释……

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;

//GRAPH
struct eg
{
	int pre,to;
	long long w;
};
eg edge[100010]={0};//linked stars
int pointer[10010]={0},edgenum,nodenum,fx,tx; long long wx;//info
int moneyp[10010]={0}; long long moneyx[10010]={0},blood; //node weight & conditions
//ALGORITHMS
long long dis[10010]; int que[70010],head,tail,prex,cache1;//spfa
int leftx,rightx,midx;//dichotomy
bool init[10010],cango[10010];//in the queue & can be visited

//AddEdge
void Insert(int at,int fromx,int tox,long long weix)
{
	edge[at].pre=pointer[fromx];
	edge[at].to=tox;
	edge[at].w=weix;
	pointer[fromx]=at;
	return;
}
//Quick Sort
void QSort(int l,int r)
{
	int mid=moneyx[(l+r)/2],i=l,j=r,x1,x2;
	while (i<=j)
	{
		while (moneyx[i]<mid) i++;
		while (moneyx[j]>mid) j--;
		if (i<=j)
		{
			x1=moneyx[i]; moneyx[i]=moneyx[j]; moneyx[j]=x1;
			x2=moneyp[i]; moneyp[i]=moneyp[j]; moneyp[j]=x2;
			i++; j--;
		}
	}
	if (i<r) QSort(i,r);
	if (l<j) QSort(l,j);
	return;
}
//Shortest Path Faster Algorithm
bool spfa(long long upat)
{
	memset(dis,0x7f,sizeof(dis));
	memset(init,false,sizeof(init));
	memset(cango,false,sizeof(cango));
	head=0; tail=0;
	for (int i=1;i<=nodenum;i++) if (moneyx[i]>upat) cango[moneyp[i]]=true;
	que[head]=1; init[1]=true; dis[1]=0;
	while (head<=tail)
	{
		cache1=que[head]; head++; init[cache1]=false;
		prex=pointer[cache1];
		while (prex>0)
		{
			if (dis[edge[prex].to]>dis[cache1]+edge[prex].w && cango[edge[prex].to]==false)
			{
				dis[edge[prex].to]=dis[cache1]+edge[prex].w;
				tail++; que[tail]=edge[prex].to;
				init[edge[prex].to]=true;
			}
			prex=edge[prex].pre;
		}
	}
	if (dis[nodenum]<=blood) return true;
	else return false;
}

int main()
{
	memset(dis,0x3f,sizeof(dis));
	memset(moneyx,0x3f,sizeof(moneyx));
	scanf("%d%d%lld",&nodenum,&edgenum,&blood);
//Input Money
	for (int i=1;i<=nodenum;i++) { scanf("%lld",&moneyx[i]); moneyp[i]=i; }
	QSort(1,nodenum);
//Input Edges
	for (int i=1;i<=edgenum*2;i+=2)
	{
		scanf("%d%d%lld",&fx,&tx,&wx);
		Insert(i,fx,tx,wx);
		Insert(i+1,tx,fx,wx);
	}
//Dichotomy & get the answer
	leftx=1; rightx=nodenum; midx=(leftx+rightx)/2;
	if (spfa(1000000010)==false)
	{
		printf("AFK\n");
		return 0;
	}
	else while (leftx<=rightx)
	{
		if (spfa(moneyx[midx])==true)
		{
			rightx=midx-1;
			midx=(leftx+rightx)/2;
		}
		else
		{
			leftx=midx+1;
			midx=(leftx+rightx)/2;
		}
	}
	if (spfa(moneyx[leftx])==true) printf("%lld",moneyx[leftx]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值