Python----DFS---骑士周游问题
这篇文章将会将一个数据结构与算法中一个很经典很重要的概念——深度优先搜索(Depth-First-Search:DFS)。。。。。。。。。(你他喵不是在标题里说了吗?)
好吧,DFS的精髓我其实也还没有弄的特别懂,估计得多用用才能理解更深吧。
!!!敲黑板!!!DFS的关键是递归,递归是真好用!!!
深度优先搜索(DFS)
什么是DFS呢,秉着能动手就绝不吵吵的原则,直接给出网上大神的博文链接:http://www.cnblogs.com/skywang12345/p/3711483.html
好吧,其实这种链接你自己都能百度到的。我就放这里做个参考,我的主要目的还是要讲一下骑士周游问题。
骑士周游问题
骑士周游问题的主要内容是什么呢?不是废话,直接上网址:http://blog.fishc.com/2554.html,这个页面对DFS问题说明的非常清楚。作者是小甲鱼大神,我在B站看的就是他的数据结构课程,不时的开个车差点闪了我的腰。
特喵的,不是说好的不说废话吗?(我错了,好吧)
好吧,直接上代码:
import datetime
from enum import Enum class Size(Enum):
X = 8 start = datetime.datetime.now()
chess = [[0 for i in range(Size.X.value)]for j in range(Size.X.value)] def nextXY(x, y, position):
global chess
if position==0 and x-2>=0 and y-1>=0 and chess[x-2][y-1]==0:
return [1, x-2, y-1]
elif position==1 and x-2>=0 and y+1<=Size.X.value-1 and chess[x-2][y+1]==0:
return [1, x-2, y+1]
elif position==2 and x-1>=0 and y-2>=0 and chess[x-1][y-2]==0:
return [1, x-1, y-2]
elif position==3 and x-1>=0 and y+2<=Size.X.value-1 and chess[x-1][y+2]==0:
return [1, x-1, y+2]
elif position==4 and x+1<=Size.X.value-1 and y-2>=0 and chess[x+1][y-2]==0:
return [1, x+1, y-2]
elif position==5 and x+1<=Size.X.value-1 and y+2<=Size.X.value-1 and chess[x+1][y+2]==0:
return [1, x+1, y+2]
elif position==6 and x+2<=Size.X.value-1 and y-1>=0 and chess[x+2][y-1]==0:
return [1, x+2, y-1]
elif position==7 and x+2<=Size.X.value-1 and y+1<=Size.X.value-1 and chess[x+2][y+1]==0:
return [1, x+2, y+1]
else:
return [0, x, y] def TravelChessBoard(x, y, tag):
global chess
chess[x][y] = tag
if tag == Size.X.value**2:
for i in chess:
print(i)
return "OK"
f = 0
for i in range(8):
flag = nextXY(x, y, i)
if flag[0]:
statues = TravelChessBoard(flag[1], flag[2], tag+1)
if statues=="OK":
return "OK"
f += 1
else:
f += 1
if f == 8:
chess[x][y] = 0 print(TravelChessBoard(2, 0, 1))
print(datetime.datetime.now() - start)
整单代码一共可以分为三个部分:变量准备部分,位置判断部分,循环递归部分。
1.变量准备部分:
- 定义了一个size枚举类,这是用于实现C语言中宏定义的功能特意定义的,当然你用别的方法也行,主要就是为了方便改变棋盘的规模。
- 定义了一个棋盘变量,是一个二维矩阵,全部元素初始化为0。也就是问题中的棋盘
2.位置判断部分:
- 函数有三个参数,分别是坐标x, y和位置position, 这个位置position先来解释一下,如下图[1]所示,在国际象棋中,按照马的走法(马走日)对于任何一个位置,马能走的地方一共有8个位置,每一个位置对应的坐标变换不一样,这里的position对应的就是8种坐标变换方式。(x, y)就是马当前所处的位置坐标

- 返回的参数为一个列表,列表中包含三个元素,第一个元素表示8个位置是否存在满足条件的下一个位置,若存在,则第二、三两个元素返回新位置的坐标,若不存在,返回原始坐标
- 判断的条件主要就是同时满足两个方面:坐标不能出界,坐标对应的位置未曾走过(位置上的值为0),两者都满足即存在满足条件的下一个位置
- 函数有三个参数,分别是坐标x, y和位置position, 这个位置position先来解释一下,如下图[1]所示,在国际象棋中,按照马的走法(马走日)对于任何一个位置,马能走的地方一共有8个位置,每一个位置对应的坐标变换不一样,这里的position对应的就是8种坐标变换方式。(x, y)就是马当前所处的位置坐标
- 循环递归函数:
def TravelChessBoard(x, y, tag):
global chess
chess[x][y] = tag
if tag == Size.X.value**2:
for i in chess:
print(i)
return "OK"
f = 0
for i in range(8):
flag = nextXY(x, y, i)
if flag[0]:
statues = TravelChessBoard(flag[1], flag[2], tag+1)
if statues=="OK":
return "OK"
f += 1
else:
f += 1
if f == 8:
chess[x][y] = 0
- 传进来的参数为当前马所在的位置(x, y),以及当前走的是第几步(tag的值)
- 第行,chess[x][y] = tag, 另当前位置的值等于当前的步数,未到达的地方则为0,以此判断一个位置是否到达过
- 第4-6行,如果步数等于棋盘的总格数(这里默认为方盘),则将棋盘打印出来,返回”OK“状态,告诉上一层递归已经寻找到解了,无需再作其它搜索了
- 第行,定义一个过程变量f = 0, 作用稍后会讲到
- 第-17行,对马的当前位置的下8个位置进行遍历,对于每一个位置,如果存在下个符合条件的位置则进入递归,将符合条件的下一个位置作为当前位置传入递归函数中,步数加1。对8个位置遍历,每次出现一个不符合条件的位置则f的值就加一。
- 第18-19行,当8个位置全部遍历完,没有一个符合条件的位置,那么此时f = 8,说明当前位置是不符合条件,那么就将当前位置的值重新置为0。
- 再说第12-15行,当深层的遍历找不到合适的位置时,递归会退回到前一层,这说明前一层的当前位置也不符合条件,那么f的值就必须加1,然后继续遍历前一层的下一个位置,以此类推。
- 最后再说13-14行,当已经找到并打印出符合条件的路径后,程序饭后”OK“状态,此时程序的递归就会从最后一层不断往前一层返回,为了加快程序结束的速度,就不继续进行剩下的遍历,每一层递归都直接返回可以了。如果不直接返回的话,程序会将所有的情况都遍历完再返回,这样时间就会非常非常非常长。YOU CAN HAVE A TRY !!!
到此这个程序也差不多讲完了,我觉得只要理解递归了,这个程序应该不难理解。
连续几天都在用递归,对递归的运用也越来越熟练,确实非常好用,真诚地希望这篇文章对你有帮助。
愿各位学业有成!!!
[1] 图拷贝自http://blog.fishc.com/2554.html,感谢鱼C工作室。
Python----DFS---骑士周游问题的更多相关文章
- 【数据结构与算法Python版学习笔记】图——骑士周游问题 深度优先搜索
骑士周游问题 概念 在一个国际象棋棋盘上, 一个棋子"马"(骑士) , 按照"马走日"的规则, 从一个格子出发, 要走遍所有棋盘格恰好一次.把一个这样的走棋序列 ...
- 骑士周游问题跳马问题C#实现(附带WPF工程代码)
骑士周游问题,也叫跳马问题. 问题描述: 将马随机放在国际象棋的8×8棋盘的某个方格中,马按走棋规则进行移动.要求每个方格只进入一次,走遍棋盘上全部64个方格. 代码要求: 1,可以任意选定马在棋盘上 ...
- poj 2488 A Knight's Journey 【骑士周游 dfs + 记忆路径】
题目地址:http://poj.org/problem?id=2488 Sample Input 3 1 1 2 3 4 3 Sample Output Scenario #1: A1 Scenari ...
- 图论 --- 骑士周游问题,DFS
A Knight's Journey Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 28630 Accepted: ...
- 骑士周游问题 --- 递归解法 --- java代码
骑士游历: 定义了向量的数组M,行数组X,列数组Y, 棋盘plane,计数器count,走动步数step 需要注意的是,递归函数的进入前的验证,原先的想法是传入来时的方向参数,可是这样的想法被实践否定 ...
- leetcode算法题121-123 --78 --python版本
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 实例输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组上操作,不能 ...
- 【数据结构与算法Python版学习笔记】目录索引
引言 算法分析 基本数据结构 概览 栈 stack 队列 Queue 双端队列 Deque 列表 List,链表实现 递归(Recursion) 定义及应用:分形树.谢尔宾斯基三角.汉诺塔.迷宫 优化 ...
- day53-马踏棋盘
马踏棋盘 1.算法优化的意义 算法是程序的灵魂,为什么有些程序可以在海量数据计算时,依旧保持高速计算? 编程中算法很多,比如八大排序算法(冒泡.选择.插入.快排.归并.希尔.基数.堆排序).查找算法. ...
- BNU 26579 Andrew the Ant 【蚂蚁】
链接: http://www.bnuoj.com/bnuoj/problem_show.php?pid=26579 http://www.bnuoj.com/bnuoj/contest_show.ph ...
随机推荐
- mysql 存储引擎的选择你会吗?
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXExMzU1NTQxNDQ4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- hdu5371 最长回文子串变形(Manacher算法)
pid=5371">http://acm.hdu.edu.cn/showproblem.php? pid=5371 Problem Description Hotaru Ichijou ...
- 数组方法-->map()
map()方法: Array.map((数组元素, 数组元素的下标, 数组本身)=>{}[,thisArray]) 1.调用时在数组内部发生了一次从 0 到 length-1 的循环: 2.返回 ...
- (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作
上午写了下单向循环链表的程序,今天下午我把双向链表的程序写完了.其实双向链表和单向链表也是有很多相似的地方的,听名字可以猜到,每个节点都包含两个指针,一个指针指向上一个节点,一个指针指向下一个节点.这 ...
- Linux I2C设备驱动编写(一)【转】
本文转载自:http://blog.csdn.net/airk000/article/details/21345457 在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即 ...
- UNDO表空间不足解决方法
确认UNDO表空间名称 select name from v$tablespace; 检查数据库UNDO表空间占用空间情况以及数据文件存放位置: select file_name,bytes/1024 ...
- Coursera Algorithms Programming Assignment 4: 8 Puzzle (100分)
题目原文:http://coursera.cs.princeton.edu/algs4/assignments/8puzzle.html 题目要求:设计一个程序解决8 puzzle问题以及该问题的推广 ...
- 9.28NOIP模拟题
9.28NOIP模拟题 题目 哈 哈哈 哈哈哈 英文题目与子目录名 ha haha hahaha 单个测试点时间限制 1秒 1秒 1秒 内存限制 256M 128M 64M 测试点数目 10 10 1 ...
- 【转】 [MySQL 查询语句]——分组查询group by
group by (1) group by的含义:将查询结果按照1个或多个字段进行分组,字段值相同的为一组(2) group by可用于单个字段分组,也可用于多个字段分组 select * from ...
- 【洛谷2624_BZOJ1005】[HNOI2008] 明明的烦恼(Prufer序列_高精度_组合数学)
题目: 洛谷2624 分析: 本文中所有的 "树" 都是带标号的. 介绍一种把树变成一个序列的工具:Prufer 序列. 对于一棵 \(n\) 个结点的树,每次选出一个叶子(度数为 ...