广度优先搜索
抓住这头牛
迷宫问题
八数码
一、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(因为如果从对头删除就再也找不到了,这一题要记录下来),要自己写,用一维数组实现,维护一个对头指针和队尾指针。