帮同学写的八数码,启发式搜索

创建两个表open,close,分别用的stl中的优先队列priority_queue和map,好久没写过代码了,bug调了半天

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <time.h>
using namespace std;
struct Item //每一个状态
{
int state[][];
int Pre; //父状态在path中的下标
int F,G,H; //估计函数 F=G+H
Item(int state[][],int Pre,int G,int H) //构造函数
{
this->Pre=Pre;
this->G=G;
this->H=H;
this->F=G+H;
for(int i=;i<;i++)
for(int j=;j<;j++)
this->state[i][j]=state[i][j];
}
bool operator <(const Item temp) const //运算符重载,用于priority_queue中元素的比较
{
return F>temp.F;
}
bool operator ==(const Item temp) const
{
for(int i=;i<;i++)
for(int j=;j<;j++)
if(state[i][j]!=temp.state[i][j]) return ;
return ;
}
}; priority_queue<Item> Open; //存储扩展出但还没有访问的表
map<int,bool> Close; //存储已经访问过的节点
vector<Item> path; //保存路径
int arrays[][]={,,,,,,,,},arraye[][]={,,,,,,,,}; //八数码初始状态和目标状态
int dx[]={,,-,},dy[]={,-,,}; //四个方向扩展
int CalcuH(const int a0[][],const int a1[][]) //CalcuH(当前状态,目标状态)计算 H,如果目标状态和当前状态某个位置数字不同,dis自加1
{
int dis=;
for(int i=;i<;i++)
for(int j=;j<;j++)
if(a0[i][j]!=a1[i][j]) dis++;
return dis;
}
bool Judge(const int p0[][],const int p1[][]) //两者逆序数奇偶性相等,看八数码是否有解
{
int ss = , ee = ;
for(int i=; i<; ++i)
for(int j=; j<i; ++j) {
if(p0[j/][j%] != && p0[j/][j%] < p0[i/][i%]) ++ss;
if(p1[j/][j%] != && p1[j/][j%] < p1[i/][i%]) ++ee;
}
return (ss&) == (ee&);
}
int GetIndex(const int a[][]) //获取hash值,将Close[t]设置为1,表示已经访问过
{
int t=;
for(int i=;i<;i++)
for(int j=;j<;j++)
t=t*+a[i][j];
return t;
}
int PrintPath(const Item p) //递归打印路径
{
if(p.Pre==-)
{
for(int i=;i<;i++)
{
for(int j=;j<;j++)
cout<<" "<<p.state[i][j]<<" ";
cout<<endl;
}
cout<<endl;
return ;
}
PrintPath(path[p.Pre]);
cout<<p.G<<" ==>"<<endl;
for(int i=;i<;i++)
{
for(int j=;j<;j++)
cout<<" "<<p.state[i][j]<<" ";
cout<<endl;
}
cout<<endl;
return ;
}
/*search()函数中的思路:
1.将初始节点放入open。(open是优先队列,f最小的节点排在队列的最前面)
2.从open中取出f最小的节点p,放入到path中,如果为目标节点,则递归打印路径。否则将该状态放入到close中,并生成他的扩展节点集P(就是将空白点往四个方向移动)。
3.对于扩展出的每个子节点 temp:
temp.calcuf(),计算f,pre,
如果temp不在close,就把它放入open中,否则不管
4.回到步骤2; 八数码无解情况判断:
初始状态和目标状态的逆序数奇偶性相同,则可到达
*/
void Search(Item s,int end[][])
{
int x,y,mx,my;
path.clear();
Open.push(s);
while()
{
Item e=Open.top();
Open.pop();
path.push_back(e);
int in=GetIndex(e.state);
Close[in]=; //标记表示已经访问过
int len=path.end()-path.begin()-; //获取e节点在path中的位置,他是扩展出的节点的父节点。
if(CalcuH(e.state,end)==)
{
//cout<<e.G<<endl;
cout<<"一共需要"<<e.G<<"步"<<endl;
PrintPath(e);
return;
}
for(int i=;i<;i++) //找到0的位置,0表示空白
for(int j=;j<;j++)
if(e.state[i][j]==)
x=i,y=j;
for(int i=;i<;i++) //向四个方向扩展
{
mx=x+dx[i],my=y+dy[i];
if(mx>||mx<||my<||my>) //判断是否跑出3*3的数组
continue;
swap(e.state[mx][my],e.state[x][y]); //将空白点与周围点交换位置
Item temp(e.state,len,e.G+,CalcuH(e.state,arraye)); //构造出新的状态节点
swap(e.state[mx][my],e.state[x][y]); //再交换回来
int index=GetIndex(temp.state); //获取hash值
if(!Close.count(index))
{
Open.push(temp);
}
}
}
return;
}
int main()
{
clock_t t=clock(),e;
Item s(arrays,-,,CalcuH(arrays,arraye));
if(Judge(arrays,arraye)) //判断是否有解
Search(s,arraye);
else
cout<<"no path"<<endl;
e=clock();
cout<<"run time : "<<e-t<<" ms"<<endl;
return ;
}

A*八数码的更多相关文章

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

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

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

    毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限 ...

  3. ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

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

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

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

  5. 双向广搜+hash+康托展开 codevs 1225 八数码难题

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

  6. UVALive 6665 Dragon’s Cruller --BFS,类八数码问题

    题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...

  7. P1379 八数码问题

    aoapc上的八数码问题,在luogu上也有类似的题,p1379,经典题目,lrj给出了一个算法,同时给出了三种判重的方法.本来想用std::queue改写一下,但是出了各种问题,只好抄代码ac掉这道 ...

  8. [cdoj1380] Xiper的奇妙历险(3) (八数码问题 bfs + 预处理)

    快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚 ...

  9. hdu 1043 Eight 经典八数码问题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 The 15-puzzle has been around for over 100 years ...

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

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

随机推荐

  1. TOP 100 MISSPELT/MISSPELLED WORDS IN ENGLISH

    acceptable accidentally accommodate acquire  acquit a lot amateur apparent argument atheist believe ...

  2. Altium Designer中Via过孔设置

  3. SpringMVC拦截器(实现登录验证拦截器)

    本例实现登陆时的验证拦截,采用SpringMVC拦截器来实现 当用户点击到网站主页时要进行拦截,用户登录了才能进入网站主页,否则进入登陆页面 核心代码 首先是index.jsp,显示链接 <%@ ...

  4. C#_Test

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Plus ...

  5. 170109、JSONP是什么

    一.JSONP的诞生 首先,因为ajax无法跨域,然后开发者就有所思考 其次,开发者发现, <script>标签的src属性是可以跨域的 把跨域服务器写成 调用本地的函数 ,回调数据回来不 ...

  6. script标签的位置

    1.在我们编写代码的时候,会在页面内使用<script>标签来写JS,虽然理论上script标签的位置放在哪里可以,但是还是有一点区别的. 2.为什么很多人把script标签放在底部: 初 ...

  7. ETL-Career RoadMap

    RoadMap: 1.Tester:sql的单体或批处理测试: 2. Application Developer 2.1 批处理手动工具(如何使用.如何调度批处理.如何生成批处理脚本): 2.2 批处 ...

  8. (3)选择元素——(15)总结(Summary)

    With the techniques that we have covered in this chapter, we should now be able to locate sets of el ...

  9. [React] React Router: Router, Route, and Link

    In this lesson we'll take our first look at the most common components available to us in react-rout ...

  10. 一个C++基于boost简单实现的线程池

    xl_blocking_queue.h ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ...