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;
}