如果题目真的要考察宽度优先搜索,那么这类题目往往具有比较大的编码难度,换个说法,就是细枝末节特别多,状态特别复杂。。
剥茧抽丝,这里以一个比较“裸”的BFS作为例子,了解一下实现BFS的一些规范。
直接把题目拿过来:
这道题如果看成了DP的话很容易写记忆化,但是,但是会爆栈。如果不信,你可以写一个递归实现的斐波那契数列然后输入一个比较大的数试一试。
求最少,最短,先考虑宽搜。
我们首先把宽搜涉及到的状态点定义出来,这就是我们之后将要入队出队的元素类型:
struct Queue { int cur,st; }q[maxn]; bool vis[maxn];
一般来说,状态都是比较复杂的,而且,千万不要忘记判重!!
接下来我们列出几种“转移方式”,也可以说搜索树往下走的时候会有几个分叉,这道题的分叉可以定义成这样:
if(q[h].cur==k) { ans=q[h].st; break; } if(q[h].cur+1<=100000&&!vis[q[h].cur+1]) {} if(q[h].cur-1>=0&&!vis[q[h].cur-1]) {} if(q[h].cur*2<=100000&&!vis[q[h].cur*2]) {}
对于结果的判断,找到结果直接退出循环就可以了,肯定是最优解。
然后就是几个搜索分支,这道题比较简单把判断直接写在了if里面,如果判断条件很复杂,建议自己实现一个check函数
t=t%maxn+1; q[t].cur=q[h].cur+1; q[t].st=q[h].st+1; vis[q[t].cur]=true;
对于每一个分支就是一个新入队的点,我们把“新”的特征表示出来之后,入队和打标记。
完整的实现如下,题目输入n和k,输出最短的移动次数。
1 #include<iostream> 2 using namespace std; 3 const int maxn=100005; 4 int n,k; 5 int ans; 6 struct Queue 7 { 8 int cur,st; 9 }q[maxn]; 10 bool vis[maxn]; 11 int main() 12 { 13 cin>>n>>k; 14 int h=0,t=1; 15 q[t].cur=n; 16 q[t].st=0; 17 while(h!=t) 18 { 19 h=h%maxn+1; 20 if(q[h].cur==k) 21 { 22 ans=q[h].st; 23 break; 24 } 25 if(q[h].cur+1<=100000&&!vis[q[h].cur+1]) 26 { 27 t=t%maxn+1; 28 q[t].cur=q[h].cur+1; 29 q[t].st=q[h].st+1; 30 vis[q[t].cur]=true; 31 } 32 if(q[h].cur-1>=0&&!vis[q[h].cur-1]) 33 { 34 t=t%maxn+1; 35 q[t].cur=q[h].cur-1; 36 q[t].st=q[h].st+1; 37 vis[q[t].cur]=true; 38 } 39 if(q[h].cur*2<=100000&&!vis[q[h].cur*2]) 40 { 41 t=t%maxn+1; 42 q[t].cur=q[h].cur*2; 43 q[t].st=q[h].st+1; 44 vis[q[t].cur]=true; 45 } 46 } 47 cout<<ans; 48 return 0; 49 }