15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了。它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失。让我们把丢失的瓷砖“X”; 拼图的目的是安排瓷砖以便它们排序为:

1 2 3 4 
5 6 7 8
9 10 11 12
13 14 15×

这里唯一合法经营是交流'X'与它共享一个边缘的瓷砖之一。作为一个例子,举动下列顺序解决了一个稍微加扰难题:

1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9×10 12 9 10×12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14×15 13 14 15×
R-> D-> R->

上一行中的字母指示哪个的“x”瓦片的邻居交换在每一步的“x”瓦片; 合法的值是'R','L','U'和'D',右,左,上,下,分别。

并非所有的难题都可以解决; 在1870年,一个叫萨姆·劳埃德的人是著名的分配难题的一个无法解决的版本,

折腾了不少人。事实上,所有你必须做的,使一个普通的益智成无法解决的一个是交换两个瓷砖(不包括课程的缺失'X'瓦)。

在这个问题中,你会写三个解决不太知名的8益智,砖组成一个三的程序

安排。


思路分析:

从第一步开始,我们每一步都有不多于四种选择:将白格向上移;向下移;向左移;向右移。这很像是做迷宫。走迷宫的任务是走到某一点就算赢。而八数码,是走到什么局面才算赢。那么队列中存放的就不是点,而是面。换句话说,就是图。现在问题变得很简单,只要你能在一张3×3的图上裸着BFS一遍,搜到目标图就算你赢了。就像迷宫的vis数组一样,我们需要对走过的局面设置标记,不要重复走。

在做这道题中学到的几样小技巧:

1. 数组直接用memcpy, memcmp对整块内存进行复制或者比较, 速度比用for循环快。

2.用typedef来定义一个新名称可以更加方便。

3.哈希表与编码的应用

    #include<stdio.h>
#include<string.h>
#define MAXN 500000 char input[];
int state[], goal[] = {,,,,,,,,};
int dir[][] = {{-,},{,},{,-},{,}}; // 上,下,左, 右
char path_dir[] = "udlr";
int st[MAXN][];
int father[MAXN], path[MAXN]; // 保存打印路径 const int MAXHASHSIZE = ;
int head[MAXHASHSIZE], next[MAXN]; void init_lookup_table() { memset(head, , sizeof(head)); } typedef int State[];
int hash(State& s) {
int v = ;
for(int i = ; i < ; i++) v = v * + s[i];
return v % MAXHASHSIZE; } int try_to_insert(int s) {
int h = hash(st[s]);
int u = head[h];
while(u) {
if(memcmp(st[u], st[s], sizeof(st[s])) == ) return ;
u = next[u];
}
next[s] = head[h];
head[h] = s;
return ;
} int bfs(){
init_lookup_table();
father[] = path[] = -;
int front=, rear=;
memcpy(st[], state, sizeof(state)); while(front < rear){
int *s = st[front]; if(memcmp(s, goal, sizeof(goal))==){
return front;
} int j;
for(j=; j<; ++j) if(!s[j])break; // 找出0的位置
int x=j/, y=j%; // 转换成行,列 for(int i=; i<; ++i){ int dx = x+dir[i][]; // 新状态的行,列
int dy = y+dir[i][];
int pos = dx*+dy; // 目标的位置 if(dx>= && dx< && dy>= && dy<){
int *newState = st[rear];
memcpy(newState, s, sizeof(int)*);
newState[j] = s[pos];
newState[pos] = ;
if(try_to_insert(rear)){
father[rear] = front; path[rear] = i;
rear++;
}
}
}
front++;
}
return -;
} void print_path(int cur){
if(cur!=){
print_path(father[cur]);
printf("%c", path_dir[path[cur]]);
}
} int main(){ while(gets(input)){
// 转换成状态数组, 'x'用0代替
for(int pos=, i=; i<strlen(input); ++i){
if(input[i]>='' && input[i]<='')
state[pos++] = input[i]-'';
else if(input[i]=='x')
state[pos++] = ;
}
int ans;
if((ans=bfs())!=-){
print_path(ans);
printf("\n");
}
}
}

【算法】BFS+哈希解决八数码问题的更多相关文章

  1. A*算法解决八数码问题 Java语言实现

    0X00 定义 首先要明确一下什么是A*算法和八数码问题? A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法也是一种启发性的算法,也是解决许多搜索问题的有效算法.算法中的距离估 ...

  2. Poj 1077 eight(BFS+全序列Hash解八数码问题)

    一.题意 经典的八数码问题,有人说不做此题人生不完整,哈哈.给出一个含数字1~8和字母x的3 * 3矩阵,如: 1  2  X            3 4  6            7  5  8 ...

  3. c++ 启发式搜索解决八数码问题

    本文对八数码问题 启发式搜索 (C++)做了一点点修改 //fn=gn+hn #include<iostream> #include<queue> #include<st ...

  4. 【基础练习】【BFS+A*】codevs1225八数码难题题解

    题目描写叙述 Description Yours和zero在研究A*启示式算法.拿到一道经典的A*问题,可是他们不会做,请你帮他们. 问题描写叙述 在3×3的棋盘上,摆有八个棋子,每一个棋子上标有1至 ...

  5. Java实现 蓝桥杯 算法提高 八数码(BFS)

    试题 算法提高 八数码 问题描述 RXY八数码 输入格式 输入两个33表格 第一个为目标表格 第二个为检索表格 输出格式 输出步数 样例输入 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 ...

  6. HDU1043 八数码(BFS + 打表)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 , 康托展开 + BFS + 打表. 经典八数码问题,传说此题不做人生不完整,关于八数码的八境界 ...

  7. HDU 1043 Eight 八数码问题 A*算法(经典问题)

    HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...

  8. A*算法 -- 八数码问题和传教士过河问题的代码实现

    前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...

  9. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

随机推荐

  1. JMeter学习(二)录制脚本(转载)

    转载自 http://www.cnblogs.com/yangxia-test 环境 Badboy  version 2.1.1 JDK: 1.7.0_67 Apache  JMeter-2.11 - ...

  2. spark快速开发之scala基础之2控制流程

    判断结构 大体与java相当.scala没有三元表达式. val num = if(1>0) 1 else 0 //相当于匿名函数 println(num) var num2 = 0 if(1& ...

  3. GreenDao存储自定义类型对象解决方案(转)

    最近公司项目选用GreenDao作为Android客户端本地数据库的对象关系映射框架.对于GreenDao虽然以往也有简单用过,但这还是笔者第一次在实际业务中使用.碰到了题目所述的两个问题,虽然在Tu ...

  4. 在 MySQL 中创建一个中文数据库

    安装完 MySQL 后,要修改密码. step 1: SET PASSWORD = PASSWORD('your new password'); step 2: ALTER USER 'root'@' ...

  5. YYKit @autoreleasepool 使用,优化内存

    写在前面 最近再看YY大神的YYKit工具,发现在代码中经常使用@autoreleasepool,特别是在与for循环搭配使用的时候.刚开始很不能理解. 先有个概念: 自己创建的对象:使用 alloc ...

  6. 【Android端 adb相关】adb相关总结

    一.什么是adb? adb的全称是:Android Debug Bridge,adb命令的构成是三部分,分别是:服务器.客户端.后台程序: (1)客户端:一个在PC上运行的客户端.可以通过shell端 ...

  7. 利用dom4j读写XML

    public static HashMap<String, String> ReadConfig() { HashMap<String, String> map=new Has ...

  8. HttpClient上传文件

    1.上传客户端代码: public static void upload() { CloseableHttpClient httpclient = HttpClients.createDefault( ...

  9. 小程序 picker 多列选择器 数据动态获取

    需求是将各校区对应各班级的数据 以两列选择器的方式展示出来,并且可以在选择完成之后记录选结果参数. 校区数据 和 班级数据 分别是两个接口,以 校区 teach_area_id 字段关联 其各班级数据 ...

  10. [z]Linux下压缩与解压

    1.压缩命令: 命令格式:tar  -zcvf   压缩文件名.tar.gz   被压缩文件名 可先切换到当前目录下.压缩文件名和被压缩文件名都可加入路径. 2.解压缩命令: 命令格式:tar  -z ...