作为一个初入ACM的蒟蒻,相信很多人在刚刚接触图的遍历搜索算法的时候也被它折磨得死去活来,那么由这道题,我们浅析一下BFS(图的广度优先搜索)算法。

先说一下BFS算法:该算法是以树形结构去遍历一个图以达到搜索的目的,由于是树形结构,所以图中每个节点只遍历一次,图所给的路径不一定全部经过,这可以在一个visit数组中做标记来实现。而广搜区别于其他搜索算法的特点就是:由根节点出发,先搜索完这个节点的全部子节点,再从这些子节点中的一个出发,搜索该节点的全部子节点,再顺次搜索下一个根节点的子节点······,概括来讲,就是在树形结构中一层层搜索,搜完这一层,再搜下一层。

BFS算法较简便的实现方法是利用队列:压入一个节点即开始遍历一个节点,然后压入它的全部子节点,队列先进先出,弹出一开始的根节点,这样它的一个子节点就成了队首,再压入它的子节点,再弹出······如果没有子节点就不压入,这样循环下去,当队列中的元素全部弹出时,一个图就遍历完了。

需要注意的是:在遍历之前队列为空时,压入根节点的同时需要手动在visit数组相应标记,而在后面根据该节点自动循环压入元素时一定要注意压入后立马标记,一定要早,一定要及时,否则在一些运算过程中可能会有未标记的状态卡进去,以致出错,一定要注意。

现在上题目:

A strange lift HDU - 1548

There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 <= Ki <= N) on every floor.The lift have just two buttons: up and down.When you at floor i,if you press the button “UP” , you will go up Ki floor,i.e,you will go to the i+Ki th floor,as the same, if you press the button “DOWN” , you will go down Ki floor,i.e,you will go to the i-Ki th floor. Of course, the lift can’t go up high than N,and can’t go down lower than 1. For example, there is a buliding with 5 floors, and k1 = 3, k2 = 3,k3 = 1,k4 = 2, k5 = 5.Begining from the 1 st floor,you can press the button “UP”, and you’ll go up to the 4 th floor,and if you press the button “DOWN”, the lift can’t do it, because it can’t go down to the -2 th floor,as you know ,the -2 th floor isn’t exist.

Here comes the problem: when you are on floor A,and you want to go to floor B,how many times at least he has to press the button “UP” or “DOWN”?

Input

The input consists of several test cases.,Each test case contains two lines.
The first line contains three integers N ,A,B( 1 <= N,A,B <= 200) which describe above,The second line consist N integers k1,k2,….kn.
A single 0 indicate the end of the input.

Output

For each case of the input output a interger, the least times you have to press the button when you on floor A,and you want to go to floor B.If you can’t reach floor B,printf “-1”.

Sample Input

5 1 5
3 3 1 2 5
0

Sample Output

3

那么这道题呢,就是说有一栋楼里有一个电梯,每一层都有一个带数字的按钮,表示电梯在这一层可以且只能上或下多少层,问从起点的楼层到终点的楼层电梯需要最少走几次,若无法到终点楼层,则输出-1.

这道题很明显用广搜更方便,因为广搜是以树的结构遍历图并且按树的层搜索,这样的话我们只需要在遍历每一层时记下层数即可,以树形结构的特点,子节点到根节点之间的层数即是两节点之间的最短路径,所以在第一次搜索到目标节点时break或结束即可,相当方便。

上代码:

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;

int n, p, q;
int lift[302];//该数组存电梯在每一楼层的可上下层数
int vis[302];//visit数组,遍历到的楼层在相应位置标记为1
int floor[302];
//这里的floor并非楼层,而是遍历结构中树的层数,即起点与当前点的路径长度
queue<int> scope;

int bfs()
{
    scope.push(p);
    vis[p] = 1;
    while(!scope.empty())
    {
        int st = scope.front();
        scope.pop();
        if(st == q) return floor[st];
        int tmp[2];
        tmp[0] = st + lift[st];
        tmp[1] = st - lift[st];
        //电梯只有上下两个运动状态,所以对应的结构相当于二叉树,直接手写就行
        for(int i = 0; i < 2; i++)
        {
            if(tmp[i] >= 1 && tmp[i] <= n && vis[tmp[i]] == 0)
            //这里就是用visit数组中的状态来限制路径了
            {
                scope.push(tmp[i]);
                vis[tmp[i]] = 1;
                floor[tmp[i]] = floor[st] + 1;
            }
        }
    }
    return -1;
}

int main()
{
    while(cin >> n && n != 0)
    {
       //初始化
        memset(vis, 0, sizeof(vis));
        memset(floor, 0, sizeof(floor));
        memset(lift, 0, sizeof(lift));
        while(!scope.empty())
        {
            scope.pop();
        }
        cin >> p >> q;
        for(int i = 1; i <= n; i++)
        {
            cin >> lift[i];
        }
        cout << bfs() << endl;
    }
    return 0;
}

话说这个题应该算最基本的BFS应用了,搞懂了这个题,就搞懂了BFS的原型,以后再遇到其他BFS的题,都是在此基础上增加花样与难度。

吾辈新人,如有疏漏,望各位大牛指正。

最后感谢网上各博客各论坛大神在我学习过程中的帮助。