美文网首页C++&数据结构与算法
广度优先搜索入门:抓住那头牛

广度优先搜索入门:抓住那头牛

作者: cherryleechen | 来源:发表于2017-10-30 14:46 被阅读38次

    问题描述

    农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛起始位于点K(0<=K<=100000)。
    农夫有两种移动方式:
    1、从X移动到X-1或X+1,每次移动花费一分钟;
    2、从X移动到2*X,每次移动花费一分钟;
    假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

    问题分析

    假设农夫起始位于点3,牛位于5。N=3,K=5,最右边是6。如何搜索到一条走到5的最短路径?


    深度优先搜索

    从起点出发,随机挑一个方向,能往前走就往前走,走不动了则回溯。 不能走已经走过的点。
    运气好的话:
    3->4->5或 3->6->5
    问题解决!
    运气不太好的话:
    3->2->4->5
    运气最坏的话:
    3->2->1->0->4->5
    要想求最优解,则要遍历所有走法。
    可以用各种手段优化,比如,若已经找到路径长度为n的解,则所有长度大于n的走法就不必尝试。
    运算过程中需要存储路径上的节点,数量较少。用栈存节点。

    广度优先搜索

    给节点分层。起点是第0层。从起点最少需n步就能到达的点属于第n层。
    第1层: 2,4,6
    第2层: 1,5
    第3层: 0
    依层次顺序,从小到大扩展节点。把层次低的点全部扩展出来后,才会扩展层次高的点。
    搜索过程(节点扩展过程):
    3
    2 4 6
    1 5
    问题解决。
    扩展时,不能扩展出已经走过的节点 。
    可确保找到的第一个解即为最优解,但是因扩展出来的节点较多,且多数节点都需要保存,因此需要的存储空间较大。用队列存节点。
    广度优先搜索算法如下
    (1) 把初始节点S0放入Open表中;
    (2) 如果Open表为空,则问题无解,失败退出;
    (3) 把Open表的第一个节点取出放入Closed表,并记该节点为n;
    (4) 考察节点n是否为目标节点。若是,则得到问题的解,成功退出;
    (5) 若节点n不可扩展,则转第(2)步;
    (6) 扩展节点n,将其不在Closed表和Open表中的子节点放入Open表的尾部
    , 并为每一个子节点设置指向父节点的指针或记录节点的层次,然后转第(2)步。

    程序实现

    #include<iostream>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int MAXN = 100001;
    int N, K;
    struct Step
    {
        int prev;
        int x;
        int steps;
        Step(int prev_, int x_, int steps_): prev(prev_), x(x_), steps(steps_) {}
        Step() {}
        Step& operator = (const Step& s)
        {
            prev = s.prev;
            x = s.x;
            steps = s.steps;
        }
    };
    bool operator < (const Step& s1, const Step& s2)
    {
        return s1.x < s2.x;
    }
    int visited[MAXN];
    queue<Step> q;
    vector<Step> v;
    stack<int> s;//存path points
    
    int main()
    {
    
        cin >> N >> K;
        memset(visited, 0, sizeof(visited));
        q.push(Step(MAXN, N, 0));
        visited[N] = 1;
        while(!q.empty())
            {
                Step tmp = q.front();
                if(tmp.x == K)
                    {
                        cout << "the optimal path length: " << tmp.steps << endl;
                        s.push(tmp.x);
                        int v_size = v.size();
                        while(tmp.prev < MAXN)
                            {
                                for(int i = 0; i < v_size; i++)
                                    if(v[i].x == tmp.prev)
                                        {
                                            tmp = v[i];
                                            s.push(tmp.x);
                                        }
                            }
                        while(!s.empty())
                            {
                                cout << s.top() << " ";
                                s.pop();
                            }
                        cout << endl;
    
                        return 0;
                    }
                if(tmp.x - 1 >= 0 && visited[tmp.x - 1] != 1)
                    {
                        q.push(Step(tmp.x, tmp.x - 1, tmp.steps + 1));
                        visited[tmp.x - 1] = 1;
                    }
                if(tmp.x + 1 <= MAXN && visited[tmp.x + 1] != 1)
                    {
                        q.push(Step(tmp.x, tmp.x + 1, tmp.steps + 1));
                        visited[tmp.x + 1] = 1;
                    }
                if(2 * tmp.x <= MAXN && visited[2 * tmp.x] != 1)
                    {
                        q.push(Step(tmp.x, 2 * tmp.x, tmp.steps + 1));
                        visited[2 * tmp.x] = 1;
                    }
                q.pop();
                v.push_back(tmp);
            }
    
    
    
        return 0;
    }
    
    

    运行结果

    相关文章

      网友评论

        本文标题:广度优先搜索入门:抓住那头牛

        本文链接:https://www.haomeiwen.com/subject/eiippxtx.html