A*八数码

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

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

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <set>
  5 #include <queue>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <map>
  9 #include <time.h>
 10 using namespace std;
 11 struct Item        //每一个状态
 12 {
 13     int state[3][3];
 14     int Pre;    //父状态在path中的下标
 15     int F,G,H;    //估计函数 F=G+H
 16     Item(int state[][3],int Pre,int G,int H)    //构造函数
 17     {
 18         this->Pre=Pre;
 19         this->G=G;
 20         this->H=H;
 21         this->F=G+H;
 22         for(int i=0;i<3;i++)
 23             for(int j=0;j<3;j++)
 24                 this->state[i][j]=state[i][j];
 25     }
 26     bool operator <(const Item temp) const        //运算符重载,用于priority_queue中元素的比较
 27     {
 28         return F>temp.F;
 29     }
 30     bool operator ==(const Item temp) const
 31     {
 32         for(int i=0;i<3;i++)
 33             for(int j=0;j<3;j++)
 34                 if(state[i][j]!=temp.state[i][j])    return 0;
 35         return 1;
 36     }
 37 };
 38
 39 priority_queue<Item> Open;    //存储扩展出但还没有访问的表
 40 map<int,bool> Close;        //存储已经访问过的节点
 41 vector<Item> path;            //保存路径
 42 int arrays[][3]={0,1,4,2,7,6,3,8,5},arraye[][3]={1,2,3,4,5,6,7,8,0};    //八数码初始状态和目标状态
 43 int dx[]={0,0,-1,1},dy[]={1,-1,0,0};    //四个方向扩展
 44 int CalcuH(const int a0[][3],const int a1[][3])    //CalcuH(当前状态,目标状态)计算 H,如果目标状态和当前状态某个位置数字不同,dis自加1
 45 {
 46     int dis=0;
 47     for(int i=0;i<3;i++)
 48         for(int j=0;j<3;j++)
 49             if(a0[i][j]!=a1[i][j])    dis++;
 50     return dis;
 51 }
 52 bool Judge(const int p0[][3],const int p1[][3])    //两者逆序数奇偶性相等,看八数码是否有解
 53 {
 54     int ss = 0, ee = 0;
 55     for(int i=0; i<9; ++i)
 56         for(int j=0; j<i; ++j) {
 57             if(p0[j/3][j%3] != 0 && p0[j/3][j%3] < p0[i/3][i%3]) ++ss;
 58             if(p1[j/3][j%3] != 0 && p1[j/3][j%3] < p1[i/3][i%3]) ++ee;
 59         }
 60     return (ss&1) == (ee&1);
 61 }
 62 int GetIndex(const int a[][3])        //获取hash值,将Close[t]设置为1,表示已经访问过
 63 {
 64     int t=0;
 65     for(int i=0;i<3;i++)
 66         for(int j=0;j<3;j++)
 67             t=t*10+a[i][j];
 68     return t;
 69 }
 70 int PrintPath(const Item p)            //递归打印路径
 71 {
 72     if(p.Pre==-1)
 73     {
 74         for(int i=0;i<3;i++)
 75         {
 76             for(int j=0;j<3;j++)
 77                 cout<<"    "<<p.state[i][j]<<" ";
 78             cout<<endl;
 79         }
 80         cout<<endl;
 81         return 0;
 82     }
 83     PrintPath(path[p.Pre]);
 84     cout<<p.G<<" ==>"<<endl;
 85     for(int i=0;i<3;i++)
 86     {
 87         for(int j=0;j<3;j++)
 88             cout<<"    "<<p.state[i][j]<<" ";
 89         cout<<endl;
 90     }
 91     cout<<endl;
 92     return 0;
 93 }
 94 /*search()函数中的思路:
 95     1.将初始节点放入open。(open是优先队列,f最小的节点排在队列的最前面)
 96     2.从open中取出f最小的节点p,放入到path中,如果为目标节点,则递归打印路径。否则将该状态放入到close中,并生成他的扩展节点集P(就是将空白点往四个方向移动)。
 97     3.对于扩展出的每个子节点 temp:
 98         temp.calcuf(),计算f,pre,
 99         如果temp不在close,就把它放入open中,否则不管
100     4.回到步骤2;
101
102 八数码无解情况判断:
103     初始状态和目标状态的逆序数奇偶性相同,则可到达
104 */
105 void Search(Item s,int end[][3])
106 {
107     int x,y,mx,my;
108     path.clear();
109     Open.push(s);
110     while(1)
111     {
112         Item e=Open.top();
113         Open.pop();
114         path.push_back(e);
115         int in=GetIndex(e.state);
116         Close[in]=1;    //标记表示已经访问过
117         int len=path.end()-path.begin()-1;        //获取e节点在path中的位置,他是扩展出的节点的父节点。
118         if(CalcuH(e.state,end)==0)
119         {
120             //cout<<e.G<<endl;
121             cout<<"一共需要"<<e.G<<"步"<<endl;
122             PrintPath(e);
123             return;
124         }
125         for(int i=0;i<3;i++)        //找到0的位置,0表示空白
126             for(int j=0;j<3;j++)
127                 if(e.state[i][j]==0)
128                     x=i,y=j;
129         for(int i=0;i<4;i++)        //向四个方向扩展
130         {
131             mx=x+dx[i],my=y+dy[i];
132             if(mx>2||mx<0||my<0||my>2)    //判断是否跑出3*3的数组
133                 continue;
134             swap(e.state[mx][my],e.state[x][y]);    //将空白点与周围点交换位置
135             Item temp(e.state,len,e.G+1,CalcuH(e.state,arraye));    //构造出新的状态节点
136             swap(e.state[mx][my],e.state[x][y]);    //再交换回来
137             int index=GetIndex(temp.state);        //获取hash值
138             if(!Close.count(index))
139             {
140                 Open.push(temp);
141             }
142         }
143     }
144     return;
145 }
146 int main()
147 {
148     clock_t t=clock(),e;
149     Item s(arrays,-1,0,CalcuH(arrays,arraye));
150     if(Judge(arrays,arraye))        //判断是否有解
151         Search(s,arraye);
152     else
153         cout<<"no path"<<endl;
154     e=clock();
155     cout<<"run time : "<<e-t<<" ms"<<endl;
156     return 0;
157 }
时间: 2024-10-26 00:06:18

A*八数码的相关文章

1225 八数码难题

1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

洛谷【P1379】八数码难题

P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. 输入输出格式 输入格式: 输入初试状态,一行九个数字,空格用0表示 输出格式: 只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊

八数码三种用时差距极大的写法

进化史,一种比一种长,一种比一种快.不过第三种似乎还不是最终形态. 第一种,傻逼级迭代加深. 去年十一月写的,那时候刚刚学迭代加深,敲了一个钟头才敲完,codevs上直接过,就没太管,觉得这是个水题.实际上呢,看后文. 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 int sx,sy,lim,

八数码的八境界 [转载]

八数码的八境界   研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor over 100 years; even if you don't know it by that name, you've seen it. I

【转】八数码问题及A*算法

一.八数码问题八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个空格,与空格相邻的棋子可以移到空格中.要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤.所谓问题的一个状态就是棋子在棋盘上的一种摆法.棋子移动后,状态就会发生改变.解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态.八数码问题一般使用搜索法来解.搜索法有广度优先搜索法.深度优

HDU 3567 Eight II(八数码 II)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo

cdoj 1380 Xiper的奇妙历险(2) [八数码问题 bfs + 预处理]

快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚至还用过A*来优化时间.不过这道题懒得写了,就一个普普通通的bfs,再加上一个stl 的map就水过了. 首先题目要求有多达10000组数据,依次搜索肯定是不行的,我试过用A*来写,第2组数据就会T掉,所以我们考虑用一个预处理.从末尾状态搜索所有可行的状态,并用一个map来存储答案.然后就很好写了.

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

题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状态逆向搜索,这样才不会超时.判重康托展开,哈希也可. POJ //#include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<string> #include<stack

洛谷OJ P1379 八数码难题 解题报告

洛谷OJ P1379 八数码难题 解题报告 by MedalPluS 题目描述   在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变.   输入格式   输入初试状态,一行九个数字,空格用0表示   输出格式 只有一行,该行只有一个数字,表示从初始状态到