广度优先搜索BFS待补

广度优先搜索

抓住这头牛

迷宫问题

八数码

一、OJ 4001 抓住这头牛
链接: link.
总时间限制: 2000ms 内存限制: 65536kB
描述
农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:

1、从X移动到X-1或X+1,每次移动花费一分钟
2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入
两个整数,N和K
输出
一个整数,农夫抓到牛所要花费的最小分钟数
样例输入
5 17
样例输出
4

策略一:深度优先搜索
从起点出发,随机挑一个方向,能往前走就往前走(扩展),走不动了则回溯。不能走已经走过的点(要判重)

要想求最优(短)解,则遍历所有的走法,可以用各种手法优化,比如,若已经找到路径长度为n的解,则所有长度大于n的走法就不必尝试。

运行过程中需要存储路径上的节点,数量较少,用栈存节点

策略二:广度优先搜索
给节点分层,起点是第0层,从起点最少需要n步就能到达的点属于第n层。

依层次顺序,从小到大扩展节点。把层次低的点全部扩展出来后,才会扩展层次更高的点。

扩展时不能扩展出已经走过的节点(要判重)
可确保找到最优解,但是因扩展出来的节点较多,且多数节点都需要保存,因此需要的存储空间较大。用对列存节点。

#include<iostream>
#include<algorithm>>
#include<cstring>
#include<cstdio>
#include<queue>   //运用到队列

using namespace std;
int N,K;
const int MAXN=100000;
int visited[MAXN+10];//判重标记,visited[i]=true表示i已经扩展过
struct Step
{
    int x;
    int steps;
    Step(int xx,int s):x(xx),steps(s){}

};//构造函数,初始化x、steps
/*相当于
Step(int xx,int s){
x=xx;
steps=s;
}
*/

queue<Step>q;//队列,即Open表
int main()
{
    cin>>N>>K;
    memset(visited,0,sizeof(visited));
    q.push(Step(N,0));
    visited[N]=1;
    while(!q.empty())
    {
        Step s=q.front();
        if(s.x==K)
        {
            cout<<s.steps<<endl;//找到的第一个节点就是最优节点
            return 0;
        }
        else {
            if(s.x-1>=0&&!visited[s.x-1])
            {
                q.push(Step(s.x-1,s.steps+1));
                visited[s.x-1]=1;
            }
            if(s.x+1<=MAXN&&!visited[s.x+1])
            {
                q.push(Step(s.x+1,s.steps+1));
                visited[s.x+1]=1;
            }
            if(s.x*2<=MAXN&&!visited[s.x*2])
            {
                q.push(Step(s.x*2,s.steps+1));
                visited[s.x*2]=1;
            }
            q.pop();
        }
    }
}

1.跟链表一样,链式队列的基本结构是数据域+指针域,不过多了两个指针——Front和Rear,有了这两个指针的限制,队列就远远不如链表那么灵活,在操作上也有别于链表。

Q.front=Q.rear=0;//头尾指针置零,此时队列为空
q.rear=q.rear++;//队尾指针加1
if((q.rear+1)%max==q.front)//表示队满
empty()作为判断容器是否为空的函数;

2.pop()是移除堆栈顶部的元素并且返回它的值
push()是把对象压入堆栈的顶部
3. Step(int xx,int s):x(xx),steps(s){}这个用法

二、Oj 7084 迷宫问题
总时间限制: 1000ms 内存限制: 65536kB
描述
定义一个二维数组:

int maze[5][5] = {

0, 1, 0, 0, 0,

0, 1, 0, 1, 0,

0, 0, 0, 0, 0,

0, 1, 1, 1, 0,

0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
输出
左上角到右下角的最短路径,格式如样例所示。
样例输入
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
样例输出
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

思路:
基础广搜。先将起始位置入队列
每次从队列拿出一个元素,扩展其相邻的4个元素(要是可以走的下可以放)入队列(要判重),直到队头元素为终点为止。队列里的元素记录了指向父节点(上一步)的指针。

队列不能用STL的queue或deque(因为如果从对头删除就再也找不到了,这一题要记录下来),要自己写,用一维数组实现,维护一个对头指针和队尾指针。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值