八数码问题:C++广度搜索实现

时间:2022-09-22 10:42:35

毕竟新手上路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++广度搜索实现的更多相关文章

  1. HDU-1043 Eight八数码 搜索问题(bfs&plus;hash 打表 IDA&ast; 等)

    题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...

  2. HDU 1043 八数码&lpar;A&ast;搜索)

    在学习八数码A*搜索问题的时候须要知道下面几个点: Hash:利用康托展开进行hash 康托展开主要就是依据一个序列求这个序列是第几大的序列. A*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...

  3. &lbrack;luogu&rsqb;P1379 八数码难题&lbrack;广度优先搜索&rsqb;

    八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...

  4. codevs1225八数码难题(搜索&&num;183&semi;)

    1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description Yours和zero在研究A*启 ...

  5. Poj 1077 eight&lpar;BFS&plus;全序列Hash解八数码问题&rpar;

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

  6. A&ast;算法 -- 八数码问题和传教士过河问题的代码实现

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

  7. ACM&sol;ICPC 之 BFS-广搜进阶-八数码&lpar;经典&rpar;&lpar;POJ1077&plus;HDU1043&rpar;

    八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...

  8. BFS&lpar;八数码&rpar; POJ 1077 &vert;&vert; HDOJ 1043 Eight

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

  9. 双向广搜&plus;hash&plus;康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description Yours和zero在研究A*启 ...

随机推荐

  1. ppmoney 总结二

    1. return false   ES6函数的扩展:箭头函数  数组 arr.map()   arr.filter() <!DOCTYPE html> <html lang=&qu ...

  2. B&period; Santa Claus and Keyboard Check 模拟

    http://codeforces.com/contest/752/problem/B uuu yyu xy xx 注意变化了之后,检查一次前面已经变化过的就好.因为可能前面的满足,但是变了后不满足. ...

  3. python TypeError&colon; &&num;39&semi;str&&num;39&semi; object does not support item assignment”

    想替换string里的空格,遍历替换提示如题错误,查询得知string类型不可更改 import string s = "2013/2/12" b = s.replace('/', ...

  4. BZOJ1895&colon; Pku3580 supermemo

    1895: Pku3580 supermemo Time Limit: 15 Sec  Memory Limit: 64 MBSubmit: 77  Solved: 47[Submit][Status ...

  5. Robot Framework自动化测试环境的搭建

    1.python-2.7.6.amd64.1394777203.msi 2.setuptools-28.0.0 3.pip-8.1.1 4.robotframework-2.8.7.win-amd64 ...

  6. EmguCV创建&sol;保存图片

    Image图片类 public Image(Bitmap bmp);//采用 Bitmap 图像创建. public Image(string fileName);//指定路径创建图像. public ...

  7. 匿名函数、高阶函数以及map

    最近学习的知识点 # 匿名函数 n = lambda name:name+"_a" print(n("alex")) # 高阶函数 # 1.参数有函数 2.返回 ...

  8. mysql删除数据库文件ibdata1后引发的故障

    进行性能测试是发现大量报错: Duplicate entry主键重复 可以看到mysql数据库中已经没有innodb引擎启动信息了 之前发现ibdata1占用了大量硬盘,为了省出空间删除了数据库ibd ...

  9. Luogu 2173 &lbrack;ZJOI2012&rsqb;网络 - LCT

    Solution $LCT$ 直接上$QuQ$ 注意$cut$ 完 需要 $d[u + c * N]--$ 再  $link$,  不然会输出Error 1的哦 Code #include<cs ...

  10. LightOJ - 1010 Knights in Chessboard&lpar;规律&rpar;

    题目链接:https://vjudge.net/contest/28079#problem/B 题目大意:给你一个nxm的棋盘,问你最多可以放几个骑士让他们互相攻击不到.骑士攻击方式如下图: 解题思路 ...