两种解法:dfs和bfs
题目描述
呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 i 层楼(1≤i≤N)上有一个数字 Ki(0≤Ki≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例如: 3,3,1,2,5 代表了 Ki(K1=3,K2=3,……),从 1 楼开始。在 1 楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有 −2−2 楼。那么,从 A 楼到 B 楼至少要按几次按钮呢?
输入格式
共二行。
第一行为三个用空格隔开的正整数,表示 N,A,B(1≤N≤200,1≤A,B≤N)。
第二行为 N 个用空格隔开的非负整数,表示 Ki。
输出格式
一行,即最少按键次数,若无法到达,则输出
-1
。输入输出样例
输入 #1复制
5 1 5 3 3 1 2 5输出 #1复制
3说明/提示
对于 100% 的数据,1≤N≤200,1≤A,B≤N,0≤Ki≤N。
首先看BFS,感觉比dfs简单
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a,b;
int fk[250];//楼层
int sg[250];//标记
memset(sg,0,sizeof(sg));
memset(fk,0,sizeof(fk));
cin>>n>>a>>b;
for(int i=1;i<=n;i++){
cin>>fk[i];
}
queue<int>f;//:楼层 队列
queue<int>st;//步数队列
f.push(a);//第一个入队
st.push(0);
sg[a]=1;//标记第一个
while(!f.empty()){
if(f.front()==b){//如果满足,已经到达b就可以退出
cout<<st.front();//输出步数
return 0;
}
int f1=f.front()+fk[f.front()];//向上搜索
int st1=st.front()+1;
if(f1<=n&&!sg[f1]){//判断是否越界和是否标记
f.push(f1);//入队
// st.push(st.front()+1);
st.push(st1);//入队
sg[f1]=1;//标记
}
f1=f.front()-fk[f.front()];//向下走
st1=st.front()+1;
if(f1>=1&&!sg[f1]){
f.push(f1);
// st.push(st.front()+1);
st.push(st1);
sg[f1]=1;
}
f.pop();
st.pop();
}
cout<<-1;
return 0;
}
接下来看dfs(啥一定是这个 0x7f7f7f7f呢,复制为如1000000000这样的数就是错误答案,到底为啥呢 )
考虑以下两点
-
是否越界;
-
当前步数是否之前抵达过且比现在抵达的步数数要少
#include<bits/stdc++.h>
using namespace std;
int ans[205],a,b,fk[205]={0},n;
void dfs(int s,int stp)
{
ans[s]=stp;
if(s+fk[s]<=n && stp+1<ans[s+fk[s]])
dfs(s+fk[s],stp+1);
if(s-fk[s]>0 && stp+1<ans[s-fk[s]])
dfs(s-fk[s],stp+1);
}
int main()
{
memset(ans,0x7f7f7f7f,sizeof(ans));//为啥一定是这个 0x7f7f7f7f呢,复制为如1000000000这样的数就是错误答案
cin>>n>>a>>b;
for(int i=1;i<=n;i++)
cin>>fk[i];
dfs(a,0);
if(ans[b]!=0x7f7f7f7f)
cout<<ans[b];
else
cout<<-1;
return 0;
}