题目描述

首先我们用一个二维数组来存储这个迷宫,刚开始的时候,小哼处于迷宫的入口处(1,1),小哈在(p,q)。其实这道题的的本质就在于找从(1,1)到(p,q)的最短路径。

此时摆在小哼面前的路有两条,我们可以先让小哼往右边走,直到走不通的时候再回到这里,再去尝试另外一个方向。

在这里我们规定一个顺序,按照顺时针的方向来尝试(即右→下→左→上)。

我们先来看看小哼一步之内可以到达的点有哪些?只有(1,2)和(2,1)。

根据刚才的策略,我们先往右边走,但右边(1,3)有障碍物,所以只能往下(2,2)这个点走。但是小哈并不在(2,2)这个点上,所以小哼还得继续往下走,直至无路可走或者找到小哈为止。

注意:并不是让我们找到小哈此题就解决了。因为刚才只是尝试了一条路的走法,而这条路并不一定是最短的。刚才很多地方在选择方向的时候都有多种选择,因此我们需要返回到这些地方继续尝试往别的方向走,直到把所有可能都尝试一遍,最后输出最短的一条路径。

例如下图就是一条可行的搜索路径:

dfs

#include<stdio.h>
int n,m,p,q,min=99999999;
int a[51][51],book[51][51];
void dfs(int x,int y,int step)
{
int next[4][2]={
{0,1},//向右走
{1,0},//向下走
{0,-1},//向左走
{-1,0},//向上走
};
int tx,ty,k;
if(x==p && y==p) //判断是否到达小哈的位置
{
if(step<min)
min=step; //更新最小值
return;
}
/*枚举四种走法*/
for(k=0;k<=3;k++)
{
/*计算下一个点的坐标*/
tx=x+next[k][0];
ty=y+next[k][1];
if(tx<1 || tx>n || ty<1 || ty>m) //判断是否越界
continue;
/*判断该点是否为障碍物或者已经在路径中*/
if(a[tx][ty]==0 && book[tx][ty]==0)
{
book[tx][ty]=1; //标记这个点已经走过
dfs(tx,ty,step+1); //开始尝试下一个点
book[tx][ty]=0; //尝试结束,取消这个点的标记
}
}
return;
} int main()
{
int i,j,startx,starty;
scanf("%d %d",&n,&m); //读入n和m,n为行,m为列
/*读入迷宫*/
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
scanf("%d %d %d %d",&startx,&starty,&p,&q); //读入起点和终点坐标
/*从起点开始搜索*/
book[startx][starty]=1; //标记起点已经在路径中,防止后面重复走
dfs(startx,starty,0); //第一个参数是起点的x坐标,以此类推是起点的y坐标,初始步数为0
printf("%d",min); //输出最短步数
return 0;
}

bfs

#include<stdio.h>
struct note{
int x; //横坐标
int y; //纵坐标
int f; //父亲在队列中的编号(本题不需要输出路径,可以不需要f)
int s; //步数
};
int main()
{
struct note que[2501]; //因为地图大小不超过50*50,因此队列扩展不会超过2500个 int a[51][51] = {0}; //用来存储地图
int book[51][51] = {0}; //数组book的作用是记录哪些点已经在队列中了,防止一个点被重复扩展,并全部初始化为0
//定义一个用于表示走的方向的数组
int next[4][2] = { //顺时针方向
{0,1}, //向右走
{1,0}, //向下走
{0,-1}, //向左走
{-1,0}, //向上走
}; int head,tail;
int i,j,k,n,m,startx,starty,p,q,tx,ty,flag; scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
scanf("%d %d %d %d",&startx,&starty,&p,&q); //队列初始化
head = 1;
tail = 1;
//往队列插入迷宫入口坐标
que[tail].x = startx;
que[tail].y = starty;
que[tail].f = 0;
que[tail].s = 0;
tail++;
book[startx][starty] = 1; flag = 0; //用来标记是否到达目标点,0表示暂时没有到达, 1表示已到达
while(head < tail){ //当队列不为空时循环
for(k=0;k<=3;k++) //枚举四个方向
{
//计算下一个点的坐标
tx = que[head].x + next[k][0];
ty = que[head].y + next[k][1];
if(tx < 1 || tx > n || ty < 1 || ty > m) //判断是否越界
continue;
if(a[tx][ty] == 0 && book[tx][ty] == 0) //判断是否是障碍物或者已经在路径中
{
book[tx][ty] = 1; //把这个点标记为已经走过。注意bfs每个点通常情况下只入队一次,和深搜不同,不需要将book数组还原
//插入新的点到队列中
que[tail].x = tx;
que[tail].y = ty;
que[tail].f = head; //因为这个点是从head扩展出来的,所以它的父亲是head,本题不需要求路径,因此可省略
que[tail].s = que[head].s+1; //步数是父亲的步数+1
tail++; }
if(tx == p && ty == q) //如果到目标点了,停止扩展,任务结束,退出循环
{
flag = 1; //重要!两句不要写反
break;
}
}
if(flag == 1)
break;
head++; //当一个点扩展结束后,才能对后面的点再进行扩展
}
printf("%d",que[tail-1].s); //打印队列中末尾最后一个点,也就是目标点的步数
//注意tail是指向队列队尾(最后一位)的下一个位置,所以这里需要减1
getchar();getchar();
return 0;
}

《啊哈算法》中P81解救小哈的更多相关文章

  1. 啊哈算法之宽搜BFS解救小哈

    简述 本算法摘选自啊哈磊所著的<啊哈!算法>第四章第三节的题目——BFS算法再次解救小哈.文中代码使用C语言编写,博主通过阅读和理解,重新由Java代码实现了一遍,以此来理解BFS算法.关 ...

  2. 解救小哈——DFS算法举例

    一.问题引入 有一天,小哈一个人去玩迷宫.但是方向感不好的小哈很快就迷路了.小哼得知后便去解救无助的小哈.此时的小哼已经弄清楚了迷宫的地图,现在小哼要以最快的速度去解救小哈.那么,问题来了... 二. ...

  3. KMP算法中next函数的理解

    首先要感谢http://blog.csdn.net/v_july_v/article/details/7041827以及http://blog.chinaunix.net/uid-27164517-i ...

  4. 简明解释算法中的大O符号

    伯乐在线导读:2009年1月28日Arec Barrwin在StackOverflow上提问,“有没有关于大O符号(Big O notation)的简单解释?尽量别用那么正式的定义,用尽可能简单的数学 ...

  5. 一步一步写算法(之prim算法 中)

    原文:一步一步写算法(之prim算法 中) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] C)编写最小生成树,涉及创建.挑选和添加过程 MI ...

  6. TextRank:关键词提取算法中的PageRank

    很久以前,我用过TFIDF做过行业关键词提取.TFIDF仅仅从词的统计信息出发,而没有充分考虑词之间的语义信息.现在本文将介绍一种考虑了相邻词的语义关系.基于图排序的关键词提取算法TextRank [ ...

  7. 问题 1690: 算法4-7:KMP算法中的模式串移动数组

    题目链接:https://www.dotcpp.com/oj/problem1690.html 题目描述 字符串的子串定位称为模式匹配,模式匹配可以有多种方法.简单的算法可以使用两重嵌套循环,时间复杂 ...

  8. 斯坦福大学公开课机器学习:machine learning system design | trading off precision and recall(F score公式的提出:学习算法中如何平衡(取舍)查准率和召回率的数值)

    一般来说,召回率和查准率的关系如下:1.如果需要很高的置信度的话,查准率会很高,相应的召回率很低:2.如果需要避免假阴性的话,召回率会很高,查准率会很低.下图右边显示的是召回率和查准率在一个学习算法中 ...

  9. 机器学习算法中如何选取超参数:学习速率、正则项系数、minibatch size

    机器学习算法中如何选取超参数:学习速率.正则项系数.minibatch size 本文是<Neural networks and deep learning>概览 中第三章的一部分,讲机器 ...

随机推荐

  1. 站点过滤器Filter

    --过滤器使用已经非常久了,今天遇到了一个小问题.也就想顺便写一个关于过滤器的博文.记录一下自己使用的感受. 实际上,Filter与Servlet及其相似,差别仅仅是FIlter的doFilter() ...

  2. 一次c3p0连接池连接异常错误的排查

    近期写了一个数据库採集程序,大概过程是将SQLSERVER数据库的数据定时採集到Oracle数据库. 1小时出一次数据,每次数据量在2W左右.环境採用Sping3+hibernate4,数据库连接池採 ...

  3. 拥抱开源——Linux C/C++程序猿必须熟悉的开源项目

    作为一个经验丰富的Linux C/C++程序猿, 肯定亲手写过各种功能的代码, 比方封装过数据库訪问的类, 封装过网络通信的类,封装过日志操作的类, 封装过文件訪问的类. 封装过UI界面库等. 也在实 ...

  4. java学习笔记:Eclipse打开现有项目

    初学JAVA,觉得困难重重. 多年来,已经习惯了微软系列的VS,现在使用Eclipse,觉得差别很大. 比如打开一个现有项目.并没有什么所谓的项目文件,如*.sln,*.cproj什么的.那怎么打开? ...

  5. 【转】Intent传递数据时,可以传递哪些类型数据?

    在Android应用的开发中,如果我们需要在不同的模块(比如不同的Activity之间)之间传递数据,通常有以下两种方法:1. 利用Intent对象携带数据通过查询Intent/Bundle的API文 ...

  6. 布局技巧1:创建可重用的UI组件(include标签)

    Android平台提供了大量的UI构件,你可以将这些小的视觉块(构件)搭建在一起,呈现给用户复杂且有用的画面.然而,应用程序有时需要一些高级的视觉组件.为了满足这一需求,并且能高效的实现,你可以把多个 ...

  7. Android 自带Base64加密解密

    Android项目引用不到以下两个java类 import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; Android有自己的base ...

  8. 使iframe随内容(target到iframe的内容)改变而自适应高度,完美解决各种获取第一个demo高度后第二个高度不变情况

    转自:http://caiceclb.iteye.com/blog/281102 很高兴,终于使用jquery实现了点击外部链接,更改iframe内容时,iframe的高度自适应问题. 失败的测试就不 ...

  9. windows 下 opencv 3.x 的安装及常见问题的解决

    1. 下载与配置 下载地址:Releases - OpenCV library(选择合适的平台和版本) 配置步骤见:VS 2013 统一修改所有工程的目录配置(以 boost.opencv3 的安装为 ...

  10. JSP-Runoob:JSP 点击量统计

    ylbtech-JSP-Runoob:JSP 点击量统计 1.返回顶部 1. JSP 点击量统计 有时候我们需要知道某个页面被访问的次数,这时我们就需要在页面上添加页面统计器,页面访问的统计一般在用户 ...