和我一起从0学算法(C语言版)(四)
第三章 搜索
深度优先搜索与宽度优先搜索
定义
深度优先搜索(DFS)
过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
宽度优先搜索(BFS)
不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

深度优先 与 宽度优先 实现的本质
深优的本质是递归,自己调用自己。
宽优的本质是利用队列经行的搜索。
深度优先与宽度优先区别
- 深优的话,占内存少,能找到最优解(一定条件下),但能很快找到接近解(优解),可能不必遍历所有分枝(也就是速度快)。时间复杂度高。
- 宽优的话,占内存多,能找到最优解,必须遍历所有分枝。
- 深度优先一般是解决连通性问题,而宽度优先一般是解决最短路径问题。
深度优先搜索
扑克牌问题
假如有编号为1 、2、3 的3 张扑克牌和编号为1 、2 、3 的3 个盒子。现在需要将这3 张扑克牌分别放到3 个盒子里面,并且每个盒子有且只能放一张扑克牌。那么一共有多少种不同的放法呢?

图解如下:

代码如下:
#include<stdio.h>
int a[10],book[10],n;
void dfs(int step) { // step表示站在第step个箱子前
int i;
if (step == n+1) { // 成立表示此时所有纸牌都放入箱子中
for (i=1;i<=n;i++)
printf("%d",a[i]);
printf("\n");
return; // 返回最近一次调用dfs函数的地方
}
for (i=1;i<=n;i++) {
if (book[i] == 0) {
a[step] = i;
book[i] = 1; // 表示纸牌已用过
dfs(step + 1); // 移步到下一个箱子
book[i] = 0; // 收回用过的纸牌
}
}
return;
}
int main() {
scanf("%d",&n);
dfs(1); // 开始站在第一个箱子前
return 0;
}
求通往 flag 的最短路程
下题先用深度优先搜索解题,再利用宽度优先搜索解题。
题目:
一只探险队从某一起点出发,寻找某处的宝藏。他们现在有一张藏宝图,为了携带更少的物资,他们需要根据地图求得通向宝藏的最短路程。(注:地图上的黑点代表障碍,无法通过)
地图示例:

深度优先解法:
图解:

思路:
利用递归调用一条路走到头,再换一条路。
代码:
#include<stdio.h>
int n,m,p,q,min=9999999; // 迷宫大小为 n*m,终点坐标为(p,q),最少步为 min
int a[51][51],book[51][51]; // a代表迷宫 ,book为所过路径标记集
void fun(int x,int y,int step) {
int next[4][2] = {{0,1}, // 向右走一步(向 y 轴正半轴平移一个单位)
{1,0}, // 向下走一步(向 x 轴正半轴平移一个单位)
{0,-1},
{-1,0}};// 类似上述,分别向左、向上走一步
int tx,ty,k;
if (x == p && y == q) {
if (step < min)
min = step;
// printf("%d\n",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; // 标记这个点已经走过
fun(tx,ty,step+1); // 开始尝试下一个点
book[tx][ty]=0; // 尝试结束,取消标记
}
}
return;
}
int main() {
void fun(int x,int y,int step);
int i, j, startx, starty;
scanf("%d %d",&n,&m);
for (i=1; i<=n; i++) // 绘制迷宫,0 为该区域可通行,1 为不可通行
for (j=1; j<=m; j++)
scanf("%d",&a[i][j]);
// 读入起点与终点坐标
scanf("%d %d %d %d",&startx,&starty,&p,&q); // 起点坐标为:(startx,starty), 终点坐标为:(p,q)
book[startx][starty]=1;
fun(startx,starty,0);
printf("%d\n",min);
return 0;
}
宽度优先解法:
图解:

思路:
利用队列推进,不断深入。
代码:
#include<stdio.h>
struct note { // 定义一个结构体
int x;
int y;
int f;
int s; // 步数
};
int main() {
struct note que[2501]; // 结构体数组
int a[51][51] = {0},book[51][51] = {0};
int next[4][2] = {{0,1},{0,-1},{1,0},{-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;
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;
que[tail].x = tx;
que[tail].y = ty;
que[tail].f = head;
que[tail].s = que[head].s+1; // 路程加一,注意对哪一个数值经行加一运算
tail++;
}
if (tx == p && ty == q) { // 判断是否达到终点
flag = 1;
break; // 退出for循环
}
}
if(flag == 1)
break; // 退出while循环
head++;
}
printf("%d",que[tail-1].s); // 注意代表路程的值为哪一个
return 0;
}
测试数据:
6 6 // 地图大小 n行 m列
0 0 0 1 0 0
0 0 1 0 0 1
1 0 0 0 0 0
0 0 0 0 1 0
0 0 1 1 0 0
0 0 0 0 0 1 // 0 为可通过,1 为障碍
1 1 5 5 // 前两个数为起点坐标,后两个为终点坐标
8 8
0 0 1 0 1 0 0 0
0 0 0 0 0 0 1 0
1 0 1 0 0 1 0 0
0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0
1 0 1 0 0 1 1 1
1 0 0 0 0 1 0 0
0 0 0 1 0 0 0 1
1 1 7 7
12 12
0 0 0 0 0 1 0 0 1 0 0 0
0 1 0 0 0 0 0 0 0 0 1 0
0 0 0 1 0 0 1 0 1 0 0 0
0 0 1 0 0 0 0 0 0 0 0 1
0 1 0 0 0 1 0 0 0 1 0 0
0 0 0 0 1 0 0 0 1 0 0 0
1 0 1 0 0 1 0 0 0 0 1 0
0 0 0 0 0 0 0 1 0 1 0 0
1 0 0 1 0 1 0 1 0 0 0 1
0 0 1 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 1 0 0 0 0 0
0 1 0 0 1 0 0 0 1 0 0 0
1 1 11 11
总结:
在数据较多时,深度优先搜索可以快速得到接近解,宽度优先搜索可以快速得到优解。(在利用12*12地图时,非常明显)
附:诗
以梦为马(或名:祖国)
——海子
我要做远方的忠诚的儿子
和物质的短暂情人
和所有以梦为马的诗人一样
我不得不和烈士和小丑走在同一道路上
万人都要将火熄灭
我一人独将此火高高举起
此火为大 开花落英于神圣的祖国
和所有以梦为马的诗人一样
我借此火得度一生的茫茫黑夜
此火为大 祖国的语言和乱石投筑的梁山城寨
以梦为马的敦煌——那七月也会寒冷的骨骼
如雪白的柴和坚硬的条条白雪 横放在众神之山
和所有以梦为马的诗人一样
我投入此火 这三者是囚禁我的灯盏 吐出光辉
万人都要从我刀口走过
去建筑祖国的语言
我甘愿一切从头开始
和所有以梦为马的诗人一样
我也愿将牢底坐穿
众神创造物中只有我最易朽
带着不可抗拒的死亡的速度
只有粮食是我珍爱 我将她紧紧抱住
抱住她 在故乡生儿育女
和所有以梦为马的诗人一样
我也愿将自己埋葬在四周高高的山上守望平静的家园
面对大河我无限惭愧
我年华虚度 空有一身疲倦
和所有以梦为马的诗人一样
岁月易逝 一滴不剩 水滴中有一匹马儿一命归天
千年后如若我再生于祖国的河岸
千年后我再次拥有中国的稻田
和周天子的雪山 天马踢踏
和所有以梦为马的诗人一样
我选择永恒的事业
我的事业 就是要成为太阳的一生
他从古至今——"日"——他无比辉煌无比光明
和所有以梦为马的诗人一样
最后我被黄昏的众神抬入不朽的太阳
太阳是我的名字
太阳是我的一生
太阳的山顶埋葬 诗歌的尸体
——千年王国和我
骑着五千年凤凰和名字叫"马"的龙
——我必将失败
但诗歌本身和太阳必将胜利
.
.
.
.
.
我知道我拖了一更。。。。别打脸。。。
以上
和我一起从0学算法(C语言版)(四)的更多相关文章
- 和我一起从0学算法(C语言版)(一)
第一章 排序 第一节 简化版桶排法 友情提示:此文章分享给所有小白,大牛请绕路! 生活中很多地方需要使用排序,价格的由低到高.距离的由远及近等,都是排序问题的体现.如果排序量较少,依靠个人能力很容易实 ...
- 和我一起从0学算法(C语言版)(三)
第二章 暴力求解(枚举法) 第一节 小学奥数题-程序求解 观察下面的加法算式: 祥 瑞 生 辉 + 三 羊 献 瑞 ------------------- 三 羊 生 瑞 气 ...
- 和我一起从0学算法(C语言版)(二)
第一章 排序 第三节 快速排序 快速排序是最常用的排序方法.快排运用的递归方法很有意思.掌握了这种排序方法可以在将来学习递归时更快入门.只是快排的思路与之前的排序方法相比较为复杂,再加担心上我的表达能 ...
- 教孩子学编程 python语言版PDF高清完整版免费下载|百度云盘|Python入门
百度云盘:教孩子学编程 python语言版PDF高清完整版免费下载 提取码:mnma 内容简介 本书属于no starch的经典系列之一,英文版在美国受到读者欢迎.本书全彩印刷,寓教于乐,易于学习:读 ...
- libnode 0.4.0 发布,C++ 语言版的 Node.js
libnode 0.4.0 支持 Windows ,提升了性能,libuv 更新到 0.10.17 版本,libj 更新到 0.8.2 版本. libnode 是 C++ 语言版的 Node.js,和 ...
- 快速排序算法C语言版
快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比 ...
- 数据结构1:数据结构与算法C语言版分析概述
本节开始将带领大家系统地学习数据结构,作为一门计算机专业大二学生的必修课程,该课程面对的目标人群为初步具备基本编程能力和编程思想的程序员(大一接触了 C 语言或者 C++).通过系统地学习数据结构,可 ...
- 【Leetcode 做题学算法周刊】第四期
首发于微信公众号<前端成长记>,写于 2019.11.21 背景 本文记录刷题过程中的整个思考过程,以供参考.主要内容涵盖: 题目分析设想 编写代码验证 查阅他人解法 思考总结 目录 67 ...
- 《数据结构与算法(C语言版)》严蔚敏 | 第五章 建立二叉树,并完成三/四种遍历算法
PS:所有的代码示例使用的都是这个图 2019-10-29 利用p126的算法5.3建立二叉树,并完成三种遍历算法 中序 后序 先序 #include<iostream> #include ...
随机推荐
- local feature和global feature的理解
在计算机视觉方面,global feature是基于整张图像提取的特征,也就是说基于all pixels,常见的有颜色直方图.形状描述子.GIST等:local feature相对来说就是基于局部图像 ...
- vSphere vSwitch网络属性配置详解
1.安全 混杂模式:把vSwitch当成是一个hub,同一台交换机上面所有的虚拟机都能接受到二层数据包. MAC地址更改:当vSwitch上面连接的某一个虚拟机MAC地址发生更改时,vSwitch是否 ...
- fiddler 限速方法
1.使用的软件下载地址: \\192.168.100.2\共享软件\开发常用\flash_team\工作软件\fiddler2setup.exe 2.注意事项 测试是,在ie浏览器环境下测试 3.软件 ...
- 云时代架构阅读笔记一——Java性能优化(一)
Java语言学习了这么长时间之后,自己对于Java编程的一些细节还是稍微有点总结,正好根据云时代架构中<Java高级开发必会的50个性能优化的细节(珍藏版)>来叙述一些我和里面的点比较相符 ...
- Oracle SQL语句记录
1.oracel 查看表空间使用情况. ) AS free_space, tablespace_name FROM dba_free_space GROUP BY tablespace_name; ) ...
- HZNU-ACM寒假集训Day11小结 贪心
1.刘汝佳紫书区间问题三大情况 1.选择不相交区间 贪心策略:一定要选择第一个区间 2.区间选点问题 贪心策略:取最后一个点 3.区间覆盖问题: n个闭区间,选择尽量少的区间覆盖一条指定线段[s,t] ...
- Python写一个简单的爬虫
code #!/usr/bin/env python # -*- coding: utf-8 -*- import requests from lxml import etree class Main ...
- Bean XML 配置(2)- Bean作用域与生命周期回调方法配置
系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of Contro ...
- TRUNC()函数——oracle
使用trunc()函数获取不同的日期: select trunc(sysdate) from dual; --今天的日期 select trunc(sysdate,'dd') from dual; - ...
- 第十五篇 用户认证auth
用户认证auth 阅读目录(Content) 用户认证 auth模块 1 .authenticate() 2 .login(HttpRequest, user) 3 .logout(request) ...