HDU 2363 Cycling

传送门
无向图,给定起点终点,找一条点权极值相差最小的路,在此基础上找最短路。
下面的代码思想是对差值进行二分,因为题目要求差值最小。差值最小是0,差值最大是输入的最大值减最小值。我们取某个差值作为限制条件,拿这个差值来限制最短路算法寻找下一个点的过程。

我想到的一种方法没有AC,而且至今没有想出问题所在,是这样的,把差值确定,但是具体的height上下限不确定,这样去限制SPFA算法,怎么在最短路算法中判断当前进行的路的差值呢?给每个点安排两个值,__min[]__max[],存放从起点走到当前点的最短路的极值,每当找下一个点时,判断下一个点的height是否会破坏中介点存放的历史道路的差值。要说明的是,差值确定的意思是小于等于差值即可,所以某个差值不连通的话,更小的差值就不用试了。另外,考虑这种方法是因为觉得__min[]__max[]的值是随着算法过程而递减和递增的,所以可以中途判断。
然而没有AC,所以肯定有问题。。感觉大概率是不能这么直接用一个差值来限制算法,判断传递过程可能存在逻辑错误,然而不知道测试数据也懒得想反例

(4月13日更新:已经想到反例。且看下图:

在这里插入图片描述

当当前差值是10的时候,错误的方法(一遍SPFA)找不到正确解,那两条虚线边意味着两种情况的无法到达。

找反例的时候先测试了一下错误方法,发现连可行性都判断不正确(在得到最后的l以后又加了一个SPFA循环,但是这样还是错的),也就是说,找到的l都不正确,也就意味着必然有一种限制情况下本来可行,但是让它给判断成不可行了。果然,这种情况被我想出来了。实锤。)

正确的方法是不仅要有差值,还要给定一个下限,这样上限也确定了,范围就确定了,下限就枚举每个点的height(正确答案肯定是以某个点的height为底),这样每次二分就要枚举NSPFA,得到一个同差值不同上下限的最小d[N];多次二分得到全局最优。因为有了上下限,所以最短路算法里直接可以根据height排除下一个点了,逻辑也就比较清晰可证了,没再出什么幺蛾子。
下面放上正确代码,有几处还是要注意的,已注释。


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

const int INF = 1e9;
const int MAXN = 101;
int N, M, T;
struct Edge
{
   
	int n, w;
};
vector<Edge> ve;
vector<int> v[MAXN];
int height[MAXN];
int d[MAXN];
bool inq[MAXN];
int _min, _max;
int diff;
int ans;

int pre[MAXN];

void init()
{
   
	_min = INF;
	_max = -1;
	ve.clear();
	for (int i = 1; i <= N; i++) v[i].clear();
	memset(pre, 0, sizeof pre);

	diff = ans = 0;        // 这句防止起点等于终点的极端情况,不然这两个都没有被显示赋初值就被输出去了。但其实想多了
}

void spfa(int s, int low, int high) // 只是定了一个明确的上下限
{
   
	queue<int> q;
	fill(inq + 1, inq + N + 1, false);
	fill(d + 1, d + N + 1, INF);

	if (height[s] < low || height[s] > high) return;            // 先初始化完d[]再判断,因为调用返回后使用d[]的值

	q.push(s);
	inq[s] = true;
	d[s] = 0;

	for (; !q.empty();)
	{
   
		int t = q.front();
		q.pop();
		inq[t] = false;
		for (int i = 0; i < v[t].size(); i++)
		{
   
			int n 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值