八数码问题: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*启 ...
随机推荐
- centos'的yum安装php的memcache扩展
centos'的yum安装php的memcache扩展 博客分类: linux 让php能使用memcached服务的扩展有两种:memcache 和 memcached 1. 先安装libmem ...
- (转)HBase 的原理和设计
转自:HBase的原理和设计 HBase架构:
- CentOS 7 AMD64安装nginx和mysql
NGINX: rpm -ivh http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.8.0-1.el7.ngx.x86_64.rpm 查看: ...
- ConterReplaceBehavior.class.php模板内容替换,如__PUBLIC__
ConterReplaceBehavior.class.php查找 __PUBLIC__ protected function templateContentReplace($content) { / ...
- OC-方法的声明和实现、匿名对象
方法声明: 方法调用: *冒号也是方法名的一部分 *同一个类中不允许两个对象方法同名 练习 给Car类设计一个方法,用来和其他车比较车速,如果快返回1,慢返回-1,相同返回0 #import < ...
- 使用Alcatraz来管理Xcode插件(转)
转自唐巧的博客:http://blog.devtang.com/blog/2014/03/05/use-alcatraz-to-manage-xcode-plugins/ 简介 Alcatraz是一个 ...
- ASP.NET MVC使用Bootstrap系统(2)——使用Bootstrap CSS和HTML元素
阅读目录 Bootstrap 栅格(Grid)系统 Bootstrap HTML元素 Bootstrap 验证样式 ASP.NET MVC创建包含Bootstrap样式编辑模板 小结 Bootstra ...
- aop实现日志(转)
文章来至于http://www.thinksaas.cn/group/topic/341436/ 第一:>>在spring的配置文件里增加以下配置 <!-- 支持 @AspectJ ...
- C#指定日期为一年中的第几周
/// <summary> /// 获取指定时间在为一年中为第几周 /// </summary> /// <param name="dt">指定 ...
- javascript取一周的日期
上代码: <script> var today = new Date(); for (var i = 0; i < 7; i++) { today.setDate(today.get ...