DFS判重问题

奇怪的电梯(洛谷)

题目背景

感谢 @yummy 提供的一些数据。

题目描述

呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 \(i\) 层楼(\(1 \le i \le N\))上有一个数字 \(K_i\)\(0 \le K_i \le N\))。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: \(3, 3, 1, 2, 5\) 代表了 \(K_i\)\(K_1=3\)\(K_2=3\),……),从 \(1\) 楼开始。在 \(1\) 楼,按“上”可以到 \(4\) 楼,按“下”是不起作用的,因为没有 \(-2\) 楼。那么,从 \(A\) 楼到 \(B\) 楼至少要按几次按钮呢?

输入格式

共二行。

第一行为三个用空格隔开的正整数,表示 \(N, A, B\)\(1 \le N \le 200\)\(1 \le A, B \le N\))。

第二行为 \(N\) 个用空格隔开的非负整数,表示 \(K_i\)

输出格式

一行,即最少按键次数,若无法到达,则输出 -1

样例 #1

样例输入 #1

5 1 5
3 3 1 2 5

样例输出 #1

3

提示

对于 \(100 \%\) 的数据,\(1 \le N \le 200\)\(1 \le A, B \le N\)\(0 \le K_i \le N\)

本题共 \(16\) 个测试点,前 \(15\) 个每个测试点 \(6\) 分,最后一个测试点 \(10\) 分。







  • 难度不大,就是注意剪枝
    分歧之处在于判重,我的版本判重是用st数组来,对于小数据来说,没问题,但量大了,会MLE
    优化之处就是用cnt数组记录每个点的步数,初始化为1e9,被更新,那么这就是第一次的点,在剪枝里用if(sum >= cnt[u]) return; 剪枝掉重复到这个点的分支,也就是判重了
  • 我还一直想错在哪,感觉也行,没问题,实际是优化不明显,因为回退到最初点,又会让一些点继续dfs,而实际早走过了,cnt数组就体现优势了

完整代码

#include <iostream>
using namespace std;
const int N = 210;
int g[N];
int n, a, b;
int ans = 1e9;
int cnt[N];
int sum;

void dfs(int u,int sum)
{
	if (sum >= ans) return;
	if (u < 1 || u > n) return;
	if (sum >= cnt[u]) return;
	if (u == b)
	{
		ans = sum;
		return;
	}

	cnt[u] = sum;
	dfs(g[u] + u;, sum + 1);
	dfs(u - g[u];, sum + 1);
}

int main()
{
	cin >> n >> a >> b;
	for (int i = 1; i <= n; i++) cin >> g[i], cnt[i] = 1e9;

	dfs(a,  0);

	if (ans == 1e9) cout << -1;
	else cout << ans;

	return 0;
}

DFS---MLE版本

#include <iostream>
using namespace std;
const int N = 210;
int g[N];
bool st[N];
int n, a, b;
int ans = 1e9;
int sum;

void dfs(int u, int sum)
{

	if (sum >= ans) return;
	if (u < 1 || u > n) return;
	if (st[u]) return;
	if (u == b)
	{
		ans = sum;
		return;
	}

	int x = g[u] + u;
	int y = u - g[u];

	st[u] = true;
	dfs(x, sum + 1);
	dfs(y, sum + 1);
	st[u] = false;
}

int main()
{
	cin >> n >> a >> b;
	for (int i = 1; i <= n; i++) cin >> g[i];

	dfs(a, 0);

	if (ans == 1e9) cout << -1;
	else cout << ans;

	return 0;
}

正确BFS版本

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 210;
int g[N];
int dist[N];
bool st[N];
int n, a, b;

void bfs()
{
	memset(dist, -1, sizeof dist);
	queue<int> q;
	q.push(a);
	dist[a] = 0;
	st[a] = true;

	while (q.size())
	{
		auto t = q.front();
		q.pop();
		if (t == b) return;
		
		for (int i = 0; i < 2; i++)
		{
			if (i == 0)
			{

				int x = g[t] + t;
				if (x > n) continue;
				if (st[x]) continue;
				st[x] = true;
				dist[x] = dist[t] + 1;
				q.push(x);
			}
			else
			{
				int y = t - g[t];
				if (y <= 0) continue;
				if (st[y]) continue;
				st[y] = true;
				dist[y] = dist[t] + 1;
				q.push(y);
			}
		}
	}
}
int main()
{
	cin >> n >> a >> b;
	for (int i = 1; i <= n; i++) cin >> g[i];

	bfs();

	cout << dist[b];

	return 0;
}
posted @ 2024-03-10 20:47  星竹z  阅读(12)  评论(0编辑  收藏  举报