奇怪的电梯
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i i i层楼 ( 1 ≤ i ≤ N ) (1{\leq}i{\leq}N) (1≤i≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3 , 3 , 1 , 2 , 5 3,3,1,2,5 3,3,1,2,5代表了 K i ( K 1 = 3 , K 2 = 3 ⋯ ) K_i(K_1=3,K_2=3{\cdots}) Ki(K1=3,K2=3⋯),从 1 1 1楼开始。在 1 1 1楼,按“上”可以到 4 4 4楼,按“下”是不起作用的,因为没有 − 2 -2 −2楼。那么,从 A A A楼到 B B B楼至少要按几次按钮呢?
输入格式
共二行。
第一行为33个用空格隔开的正整数,表示 N , A , B ( 1 ≤ N ≤ 200 , 1 ≤ A , B ≤ N ) N , A , B ( 1 ≤ N ≤ 200 , 1 ≤ A , B ≤ N N,A,B(1≤N≤200, 1≤A,B≤N)N,A,B(1≤N≤200,1≤A,B≤N N,A,B(1≤N≤200,1≤A,B≤N)N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为 N N N个用空格隔开的非负整数,表示 K i K_i Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出 − 1 -1 −1。
深度优先搜索
如果单纯的暴力搜索,会有很多重复的搜索,比如某一次搜索中已经来过了 1 1 1楼,但是进过了一番波折又来到了 1 1 1楼,那么势必会重复之前那个过程,所以之前来过的楼就不能再来一次了。
#include
#include
using namespace std;
int floor[205],N;
bool map[205];
int Min = INT_MAX; //获取int的最大值
void dfs(int,int,int,int);
int main()
{
int begin,end,t;
cin>>N>>begin>>end;
for(t=1;t<=N;t++)
{
cin>>floor[t];
}
if(begin == end) {
cout << 0 << endl;
return 0;
}
dfs(begin,end,begin,0);
if(Min==INT_MAX)
cout<<-1;
else cout<<Min;
}
void dfs(int begin,int end,int now,int times)
{
if(now==end)
{
if(times<Min)
{
Min=times;
}
return;
}
if(now-floor[now]>=0&&!map[now])
{
map[now]=true;
dfs(begin,end,now-floor[now],times+1);
map[now]=false;
}
if(now+floor[now]<=N&&!map[now])
{
map[now]=true;
dfs(begin,end,now+floor[now],times+1);
map[now]=false;
}
}
结果超时了两个点,所以还需要进一步的剪枝,对于如何剪枝,原则是如果这个搜索是没有必要的就是把它剪掉,比如求几个数相乘等于一个数,如果发现在相乘的过程中已经大于这个数了,且乘的数都大于 1 1 1,那么就不要用搜下去了。
对于这道题因为我们是在寻找最小值,且每一次搜索值都会增加,所以在搜的过程中如果发现值已经大于最小值了,就不要再搜了。
改进后的代码
#include
#include
using namespace std;
int floor[205],N;
bool map[205];
int Min = INT_MAX;
void dfs(int,int,int,int);
int main()
{
int begin,end,t;
cin>>N>>begin>>end;
for(t=1;t<=N;t++)
{
cin>>floor[t];
}
if(begin == end) {
cout << 0 << endl;
return 0;
}
map[begin]=true;
dfs(begin,end,begin,0);
if(Min==INT_MAX)
cout<<-1;
else cout<<Min;
}
void dfs(int begin,int end,int now,int times)
{
if(now==end)
{
if(times<Min)
{
Min=times;
}
return;
}
if(times>Min)
return;
if(now-floor[now]>=0&&!map[now-floor[now]])
{
map[now]=true;
dfs(begin,end,now-floor[now],times+1);
map[now]=false;
}
if(now+floor[now]<=N&&!map[now+floor[now]])
{
map[now]=true;
dfs(begin,end,now+floor[now],times+1);
map[now]=false;
}
}
完美通过!!
广度优先搜索
这道题在讨论区大家都比较推荐 b f s bfs bfs,于是我也来做一下顺便复习一下
#include
#include //使用stl
using namespace std;
int Floor[205], N;
int map[205];
int flag, Begin;
queue<int> q; //创建一个队列,int可以是任意的数据类型
int bfs(int, int);
int main()
{
int end, t;
cin >> N >> Begin >> end;
for (t = 1; t <= N; t++)
{
cin >> Floor[t];
}
t = bfs(Begin, end);
if (flag)
cout << t;
else
cout << -1;
}
int bfs(int now_floor, int end)
{
int temp_floor;
q.push(now_floor); //入队
while (q.size())
{
temp_floor = q.front(); //返回队列最前面的值
q.pop(); //弹出最后一个元素,但返回值是void
if (temp_floor == end)
{
flag = 1;
return map[temp_floor];
}
if (temp_floor - Floor[temp_floor] > 0 && !map[temp_floor - Floor[temp_floor]] &&
temp_floor - Floor[temp_floor] != Begin)
{
q.push(temp_floor - Floor[temp_floor]);
map[temp_floor - Floor[temp_floor]] = map[temp_floor] + 1;
}
if (temp_floor + Floor[temp_floor] <=N && !map[temp_floor + Floor[temp_floor]] &&
temp_floor + Floor[temp_floor] != Begin)
{
q.push(temp_floor + Floor[temp_floor]);
map[temp_floor + Floor[temp_floor]] = map[temp_floor] + 1;
}
}
}
可以看到使用bfs就不用考虑剪枝这种细节,但是bfs编写起来麻烦了一点