【萌新向】c语言求解八数字(华容道)问题

前言 

这次小学期大作业给了几道编程题让我们自己选,其中就有一道求解八数字问题。刚拿到这个题的时候头疼得不行,还得用c语言写,大一才学了这么点东西哪能做得出来,哈希表,搜索代码一个没学。后来一想可能是想考察我们自主学习的能力?那就开整吧。

本文仅用于记录自己学习过程,仅模拟给和我同进度的同学讲解的语气,并非攻略教程,难免会有错误且代码写得烂,求轻喷。

思路参考:(8条消息) 如何通过编程解决华容道问题?_程序人生的博客-优快云博客 

感谢大佬理清做题思路。

一、问题分析

先看看题目要求:

规则:8数码拼图,9宫格中随机放置数字0-8,0作为空位可与上下左右的数字交换,最终排列为:

012

345

678

后面还给了几个函数的函数头,略。

 emmm这题干讲了,但又什么都没讲,自由发挥了属于是。

首先得有个棋盘,这个棋盘是自己生成还是输入呢?为了提高难度我选择了自己生成随机棋盘。

其次是需要的算法。华容道其实就像走迷宫问题,0就是我们当前所在位置,0在一个3x3的棋盘里进行上下左右移动,最终目的就是恢复成012345678这样的状态。这道题我们是想要求解所有可能的解还是只要一个解就行呢?我认为是求解出一个就行了,这个解最好是最优解(也就是步骤最少的解),那么胜利的法则就决定了:宽度优先搜索。

百度宽搜可得

广度优先搜索使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:

1、把根节点放到队列的末尾。

2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。

3、找到所要找的元素时结束程序。

4、如果遍历整个树还没有找到,结束程序。

 而我们不能只搜索,还要找出解并且把它打印出来。那么就可以参考链表的方法,每次搜索的时候创建一个结点,这个结点存储它的棋盘,以及它的上一步的结点和当前走的方向,就像链表一样把它们连接起来。这样一旦发现了解,只需要顺藤摸瓜,抓住成功的那个结点一个个往回拽出来即可。

那么接下来就是定义需要的数据结构。首先定义一个结构体保存棋盘,再定义一个结构体保存结点,接着是定义一个链表队列。

好像大功告成了?但还有一个问题,如果第一步往右走,第二步又往左走了,这不就回到原来的状态了吗,势必会造成出现许多不必要的步骤的情况。那么如何解决呢?把所有出现过的状态都存起来!用什么来存呢?反观我们这学期学的的基础的数据结构,如果用顺序表链表来存,显然是不行的。因为9宫格有多少种状态……9的9次方387420489种,虽然实际计算时不可能每种状态都经历一遍,但也是个不小的数字!以顺序表链表的搜索的时间复杂度来看,会非常慢。怎么办呢?我们知道顺序表的查询指定下标的时间复杂度是O(1),也就是知道下标就能立刻查询到它。如果我们用一种特殊的方法把要查询的数据转成一个下标值,然后把它存储到下标位置,是不是可以以O(1)的时间复杂度查询到出现过的棋盘状态呢?答案是可以,这种数据结构就叫哈希表。

好,链表队列,哈希表,我们的数据结构就这么决定了。

二、技术准备

首先定义结构体。链式队列的代码大家应该很容易写出来,这次新加了一个之前没接触过的哈希表的代码,其实很好理解,它就是一个有特殊功能,存储时较为特别的顺序表。

typedef struct{ //a来存储棋盘,i,j存储0的当前位置(别问我为什么用char数组,因为题目要求)
	char a[N*N];
	char i,j;
}G;

typedef struct node{
	struct node *last; //存步骤中它的上一个结点 
	struct node *next; //存链表中它的下一个结点
	int status; //存棋盘状态  
	int dir; //这一步走的方向
}Node;

typedef struct{
	Node *head,*tail; //队列的队头和队尾指针
	int size; //队列长度
}List;

typedef struct{
	unsigned max_size; //哈希表最大容量capacity
	unsigned cur_size; //哈希表当前容量
	int* table; //存储用的数组
}hash;

接下来是他们的函数。

//队列部分 
void init_list(List *lp){ //初始化队列
	lp->head=(void*)0;
	lp->tail=(void*)0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值