八数码问题:C++广度搜索实现
毕竟新手上路23333,有谬误还请指正。 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限制又会有很多情况无法找到,然后果断放弃,改用广度搜索。 如果要改善代码效率还可以用双向搜索,即从起始状态和最终状态同时搜索,找到相同状态,这样搜索时间会缩短一半。此外还可以用A*(启发式算法)会显得高端很多。
题目要求: 在一个3*3的棋盘上,随机放置1到8的数字棋子,剩下一个空位。数字可以移动到空位(编程时,空位可用0代替,且可以理解为是空位的上、下、左、右移动),经过若干次移动后,棋局到达指定目标状态。 数组表示棋局状态。用函数表示空格(0)的移动,使用函数具有前提条件,满足条件才可以使用。 用广度优先或深度优先搜索求解。还可以使用启发式求解,以提高搜索效率。 要求: ① 编程求解问题; ② 给出中间状态; ③ 给出解序列(函数调用序列)
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <sstream>
#include <deque>
#include <functional>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <stack>
#include <set>
#include <numeric>
#include <utility>
#include <cstring>
#include <fstream> using namespace std;
int board[]; //初始状态,一维数组模拟二维
int destboard[]; //目标状态
int dx[] = {-, , , }; //数字0的移动偏移量
int dy[] = {, , , -};
map<int, bool> mark; //记录已搜索的状态 int lists(int i, int j)
{
return i* + j; //返回i, j二维数组的一维位置
} int judge() //运算前判断是否可以找到一种对于初末状态可行的变换
{
int first_d[],last_d[],i,j=,k,rank1=,rank2=;
for(i=;i<=;i++) //初状态赋值给first_d[10]
{
while()
{
if(j==){j=;}
if(j==){j=;}
first_d[i]=destboard[j];
j++;
break;
}
}
j=;i=;
for(k=;k<=;k++) //最终状态赋值给last_d[10]
{
while()
{
last_d[k]=board[lists(i, j)];
j++;
if(j==){i++;j=;}
break;
}
} for(j=;j<=;j++) //计算初状态的奇偶性
{
for(i=;i<j;i++)
{
if(first_d[i]>first_d[j]&&first_d[i]!=&&first_d[j]!=){rank1++;}
}
} for(j=;j<=;j++) //计算末状态的奇偶性
{
for(i=;i<j;i++)
{
if(last_d[i]>last_d[j]&&last_d[i]!=&&last_d[j]!=){rank2++;}
}
}
int a1=rank1%,a2=rank2%;
if(a1!=a2){return ;} //判断奇偶性是否相同,相同才可以从出状态变到末状态
else{return ;}
} struct Stat //结构体三个参数
{
int step; // 步数
int board[]; // 状态
Stat(int *b, int s=)
{
memcpy(this->board, b, sizeof(int)*); //对状态的赋值操作
step = s;
}
}; bool ok(int *b) // 判断是否到已经达目标状态
{
for(int i=; i<=; ++i)
for(int j=; j<=; ++j)
{
if(b[lists(i, j)] != destboard[lists(i, j)])
return false;
}
return true;
} int Bfs()
{
int judge_first=judge();
ofstream ofs; //建立数据外存文件
ofs.open("output.dat");
if(judge_first==){cout<<"不存在"<<endl;return ;}
if(judge_first==)
{
queue<Stat> que; //建队que
que.push(Stat(board, )); // 初始状态入队
while(que.size())
{
int m=, mk=; // 记录状态m,以及基数mk
Stat p = que.front(); //取出队头元素
for(int i=; i<=; ++i)
{
for(int j=; j<=; ++j)
{
ofs<<p.board[lists(i, j)]<<" ";
}
ofs<<endl;
}
ofs<<endl; que.pop(); //出队 if(ok(p.board))
{
return p.step; // 到达目标则返回最短步数
} for(int i=; i<=; ++i) // 这个是为了标记初始状态,不能遗漏
for(int j=; j<=; ++j)
{
m+=p.board[lists(i, j)]*mk;
mk*=;
}
if(!mark.count(m)) // 未标记则标记
mark[m] = true; for(int k=; k<; ++k) // 四个方向搜索
{
Stat n(p.board, p.step+); // n是下一步搜索的状态
int zx, zy; // zx,zy存放当前状态0的位置 for(int i=; i<=; ++i) // 搜索当前状态的0的位置
for(int j=; j<=; ++j)
{
if(p.board[lists(i,j)]==)
{
zx = i;
zy = j;
break;
}
if(p.board[lists(i,j)]==)
break;
} int nx = zx+dx[k]; //下一个状态的0的位置
int ny = zy+dy[k];
m = ; //标记状态
mk = ;
swap(n.board[lists(nx,ny)],n.board[lists(zx, zy)]); //交换 for(int i=; i<=; ++i)
for(int j=; j<=; ++j)
{
m+=n.board[lists(i, j)]*mk;
mk*=;
}
if(!mark.count(m))
{
mark[m] = true;
que.push(n); //若未搜索过,则入队
}
}
}
ofs.close(); //结束外存
return ;
}
return ;
} int main()
{
cout<<"广度搜索八数码问题:\n";
cout<<"请输入初始状态用0-8表示\n";
memset(board, , sizeof(board));
for(int i=; i<=; ++i)
for(int j=; j<=; ++j)
scanf("%1d", &board[lists(i, j)]); cout<<"请输入结束状态\n";
for(int m=;m<=;m++){scanf("%d",&destboard[m]);}
for(int m=;m<=;m++){scanf("%d",&destboard[m]);}
for(int m=;m<=;m++){scanf("%d",&destboard[m]);}
mark.clear(); cout<<"准备搜索...\n";
system("pause");
cout<<"搜索中.....\n"; int t=Bfs();
cout<<"搜索完毕,过程已经以文件的形式存储\n";
if(t==){cout<<"没有找到"<<endl;}
else{cout<<"深度为:"<<t<< endl;}
system("pause");
return ;
}
输入初始状态和最终状态,中间过程会生成在”output.dat”中。
八数码问题:C++广度搜索实现的更多相关文章
- HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)
题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...
- HDU 1043 八数码(A*搜索)
在学习八数码A*搜索问题的时候须要知道下面几个点: Hash:利用康托展开进行hash 康托展开主要就是依据一个序列求这个序列是第几大的序列. A*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...
- [luogu]P1379 八数码难题[广度优先搜索]
八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...
- codevs1225八数码难题(搜索·)
1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description Yours和zero在研究A*启 ...
- Poj 1077 eight(BFS+全序列Hash解八数码问题)
一.题意 经典的八数码问题,有人说不做此题人生不完整,哈哈.给出一个含数字1~8和字母x的3 * 3矩阵,如: 1 2 X 3 4 6 7 5 8 ...
- A*算法 -- 八数码问题和传教士过河问题的代码实现
前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...
- ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)
八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...
- BFS(八数码) POJ 1077 || HDOJ 1043 Eight
题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...
- 双向广搜+hash+康托展开 codevs 1225 八数码难题
codevs 1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启 ...
随机推荐
- sudo 出现unable to resolve host 解决方法
inux 环境, 假设这台机器名字叫dev(机器的hostname), 每次执行sudo 就出现这个警告讯息:sudo: unable to resolve host dev虽然sudo 还是可以正常 ...
- Java web 使用页面压缩
借助类,相关依赖: <!-- https://mvnrepository.com/artifact/net.sourceforge.pjl-comp-filter/pjl-comp-filter ...
- linux中快速清空文件内容的几种方法
这篇文章主要介绍了linux中快速清空文件内容的几种方法,需要的朋友可以参考下 $ : > filename $ > filename $ echo "" > f ...
- ecshop show_message
格式lib_main.php show_message(内容, array(返回列表,继续编辑), array(连接地址一,链接地址二, 'info',false); true:自动跳转 输出: fu ...
- css 常用代码解析
.cBan_1 .e2-pro li a{ display: block; -webkit-transition: all 0.3s linear;transition: all 0.3s linea ...
- underflow 、overflow 下溢和上溢
在strtoull函数返回值中,就提到上溢和下溢的问题,现在把这俩个概念拿出来涨涨见识! 上溢 Overflow 是当一个超长的数据进入到缓冲区时,超出部分被写入上级缓冲区,上级缓冲区存放的可能是数 ...
- thinkphp学习笔记13-15集
13集: ThinkPHP3.1.3使用视频教程--后台登录验证与自动运行方法_标清.flv 14集: ThinkPHP3.1.3使用视频教程--自定义SESSION处理DB驱动与添加Redis处理驱 ...
- regsvr32的使用
注册器是: DllRegisterServer 命令就是: regsvr32 不是regsrv32.
- 我常用的eclipse快捷键
重写父类方法:右键点击, 进source,进override/implement 单行注释(或多行注释) Ctrl+/ 文档注释:shift+alt+J 整块注释: Ctrl+shift+/ 取消整块 ...
- 工具介绍 - VSCommands
VSCommands 一个Visual Studio的轻量级扩展工具 地址:http://vscommands.squaredinfinity.com/home 1.可以设置自动隐藏显示主菜单栏,设置 ...