警示后人,不管你错了啥都可以进来看看
查看原帖
警示后人,不管你错了啥都可以进来看看
312820
Chinshyo楼主2023/8/14 14:22

看看我交了几次就知道这题坑有多少了。感觉比有些蓝题写起来都痛苦。 所以为什么不是蓝题

第二篇题解有两处错误。

本人dij+二分,就是看的第二篇题解。

总结一下所有的坑 我全踩了 :

  1. 如果你的程序连样例都过不去,一直死循环,检查调用dij的时候是否初始化了!dis数组和vis数组每次都要初始化!
for(int i = 1; i <= n; i++) {
    dis[i] = LONG_LONG_MAX;
    vis[i] = 0;	
}
  1. 第二篇题解的二分写的有问题。当区间收缩的时候,他的区间始终都没有包括mid。然而mid很有可能就是最优解。
  2. 如果你WA Subtask后两个点,注意到终点的时候血量可以是0。这里第二篇题解也是错的。

错误写法

if(dis[n] < b) return true;
	return false;

正确写法

if(dis[n] <= b) return true;
	return false;
  1. 如果你不开O2 0分,开O2RE,或者莫名其妙TLE,检查你的前向星数组是不是开了两倍!这可是无向图!

  2. 检查dis数组、头尾指针开没开long long!没开会WA,边权加起来会爆int。

  3. 如果你WA了Subtast2 第一个点(好像是这个吧),检查判断了第一个节点符不符合二分答案给出的钱的限制!

if(f[1] > cst) return false;
  1. 如果你学习的《算法竞赛进阶指南》上的dij写法,用大根堆写的小根堆,push和取top的时候记得取反!!!这个错误太智障了!
q.push(make_pair(-dis[y], y));
pair <ll, int> p = q.top();
q.pop();
ll dist = -p.first, x = p.second;
  1. 还是如果你死循环了,如果你是这种写法
if(chk(mid)) {
	r = mid;
} else {
	l = mid + 1;
} 

改成

if(tmp == 1) {
	r = mid;
} else {
	l = mid + 1;
} 

我也不太懂为什么

  1. 如果你WA#5,把函数出口换个位置。至于为什么我也不懂。(注释的是原来的位置)
bool chk(ll cst) {
	for(int i = 1; i <= n; i++) {
		dis[i] = LONG_LONG_MAX;
		vis[i] = 0;	
	}
	
	q.push(make_pair(0, 1));
	dis[1] = 0;
	if(f[1] > cst) return false;
	while(!q.empty()) {
		pair <ll, int> p = q.top();
		q.pop();
		ll dist = -p.first, x = p.second;
		
//		if(x == n) {
//			if(dis[n] > b) return false;
//			return true;
//		}
		if(vis[x]) continue;
		vis[x] = true;
		for(int i = head[x]; i > 0; i = nxt[i]) {
			ll y = ver[i], c = edge[i];
			if(dist + c <= dis[y] && f[y] <= cst)  {
				dis[y] = dist + c;
				q.push(make_pair(-dis[y], y));
			}
		}
	}
	if(dis[n] <= b) return true;
	return false;
}
  1. 还是二分的问题,关注你的区间开闭情况,结束条件。

希望大家早日AC,不要重蹈覆辙

2023/8/14 14:22
加载中...