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

创建两个表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. Entity Framework with MySQL 学习笔记一(安装)

    声明 :  数据库是Mysql,本人的程度只到会写sql语句(不会储蓄过程), c# 会基本的ADO.NET数据库访问,LINQ基础. 这篇只做个人学习|温习作用. 新手可以参考,也请高手指正错误, ...

  2. Android中开发Service

    Service的开发分为两个步骤:定义Service和配置Service1.定义Service定义一个Service子类继承于Service2.配置Service在AndroidManifest.xm ...

  3. 8.2.1.15 ORDER BY Optimization ORDER BY 优化

    8.2.1.15 ORDER BY Optimization ORDER BY 优化 在一些情况下, MySQL 可以使用一个索引来满足一个ORDER BY 子句不需要做额外的排序 index 可以用 ...

  4. 设计模式(八):Bridge桥接模式 -- 结构型模式

    1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...

  5. Delphi default属性

    Delphi default属性 Delphi控件指定属性的时候可以加上Default关键字,例如property Color default clBtnface.一直以为这个是构造类的时候的默认值, ...

  6. 2015.9.11模拟赛 codevs 4159【hzwer的迷の数列】

    题目描述 Description hzwer找了一个人畜无害的迷の数列…… 现在hzwer希望对这个数列进行一些操作,请你来回答hzwer的问题. 操作一:查询第i个数的大小 操作二:把第i个数的大小 ...

  7. iOS单元测试(作用及入门提升)

    由于只是一些简单实用的东西,学学还是挺不错的.其实单元测试用的好,开发起来也会快很多.单元测试对于我目前来说,就是为了方便测试一些功能是否正常运行,还有调试接口是否能正常使用.有时候你可能是为了测试某 ...

  8. js时间基本操作

    js 获取前一天的时 var today=new Date(); var yesterday_milliseconds=today.getTime()-1000*60*60*24; var yeste ...

  9. IOS设计模式学习(19)策略

    1 前言 面向对象软件设计中,我们可以把相关算法分离为不同的类,成为策略.与这种做法有关的一种设计模式成为策略模式. 2 详述 2.1 简述 策略模式中得一个关键角色是策略类,它为所有支持的或相关的算 ...

  10. 企业版IDP的申请及“In House”发布

    企业版IDP,即iOS Development Enterprise Program.注意是$299/Year那种,并不是$99/Year的那种. 这种方式的IDP其最大的好处在于:可以发布“In H ...