人生第一个A*算法~好激动……

八数码难题……又称八数码水题,首先要理解一些东西:

1.状态可以转化成整数,比如状态:   1 2 3

                  4 5 6

                  7 8 0

  可以转化成:123456780这个整数

2.看上去有9*9种不同状态,实际上只有9!种(即9*8*7*6*5*4*3*2*1)种状态,哈希表大小开成一个大素数即可,每次用这个大素数去对当前的状态(整数)取余获得哈希表的键值

3.移动一个数码到0这个位置可以理解成0这个数码移动到四周的数码的位置

我先用广搜水过,速度大约是20ms左右:

 1 #include <iostream>
2 #include <queue>
3 #include <cstdlib>
4 #define hash(x) (x%14233333)
5 using namespace std;
6 const int _end=123804765;
7 int _sta;
8 bool h_tab[14233333];
9 queue<int> que,tque;
10 int move(int key,char c)
11 {
12 int p0=1,kb=key,_map[3][3],x0,y0;
13 while(1){if(kb%10==0)break;p0++,kb/=10;}
14 kb=key,x0=(9-p0)/3,y0=(9-p0)%3;
15 for(int i=2;i>=0;i--)for(int j=2;j>=0;j--)_map[i][j]=kb%10,kb/=10;
16 switch(c)
17 {
18 case 'l':if(y0==0)return key;swap(_map[x0][y0],_map[x0][y0-1]);break;
19 case 'r':if(y0==2)return key;swap(_map[x0][y0],_map[x0][y0+1]);break;
20 case 'u':if(x0==0)return key;swap(_map[x0][y0],_map[x0-1][y0]);break;
21 case 'd':if(x0==2)return key;swap(_map[x0][y0],_map[x0+1][y0]);break;
22 default:break;
23 }
24 kb=0;
25 for(int i=0;i<3;i++)for(int j=0;j<3;j++)kb=kb*10+_map[i][j];
26 return kb;
27 }
28 int main()
29 {
30 cin>>_sta;
31 if(_sta==_end)cout<<0,exit(0);
32 que.push(_sta),tque.push(0),h_tab[hash(_sta)]=1;
33 while(!que.empty())
34 {
35 int _new=move(que.front(),'u');
36 if(_new==_end)cout<<tque.front()+1,exit(0);
37 if(!h_tab[hash(_new)])h_tab[hash(_new)]=1,que.push(_new),tque.push(tque.front()+1);
38 _new=move(que.front(),'d');
39 if(_new==_end)cout<<tque.front()+1,exit(0);
40 if(!h_tab[hash(_new)])h_tab[hash(_new)]=1,que.push(_new),tque.push(tque.front()+1);
41 _new=move(que.front(),'l');
42 if(_new==_end)cout<<tque.front()+1,exit(0);
43 if(!h_tab[hash(_new)])h_tab[hash(_new)]=1,que.push(_new),tque.push(tque.front()+1);
44 _new=move(que.front(),'r');
45 if(_new==_end)cout<<tque.front()+1,exit(0);
46 if(!h_tab[hash(_new)])h_tab[hash(_new)]=1,que.push(_new),tque.push(tque.front()+1);
47 que.pop(),tque.pop();
48 }
49 return 0;
50 }

又用了双向广搜试了试,速度大概是10ms左右:

 1 #include <iostream>
2 #include <queue>
3 #include <cstdlib>
4 #define hash(x) (x%14233333)
5 using namespace std;
6 const int _end=123804765;
7 int _sta;
8 unsigned short th_tab[2][14233333];
9 bool h_tab[2][14233333];
10 queue<int> que[2];
11 int move(int key,char c)
12 {
13 int p0=1,kb=key,_map[3][3],x0,y0;
14 while(1){if(kb%10==0)break;p0++,kb/=10;}
15 kb=key,x0=(9-p0)/3,y0=(9-p0)%3;
16 for(int i=2;i>=0;i--)for(int j=2;j>=0;j--)_map[i][j]=kb%10,kb/=10;
17 switch(c)
18 {
19 case 'l':if(y0==0)return key;swap(_map[x0][y0],_map[x0][y0-1]);break;
20 case 'r':if(y0==2)return key;swap(_map[x0][y0],_map[x0][y0+1]);break;
21 case 'u':if(x0==0)return key;swap(_map[x0][y0],_map[x0-1][y0]);break;
22 case 'd':if(x0==2)return key;swap(_map[x0][y0],_map[x0+1][y0]);break;
23 default:break;
24 }
25 kb=0;
26 for(int i=0;i<3;i++)for(int j=0;j<3;j++)kb=kb*10+_map[i][j];
27 return kb;
28 }
29 int main()
30 {
31 cin>>_sta;
32 if(_sta==_end)cout<<0,exit(0);
33 que[0].push(_sta),que[1].push(_end),h_tab[0][hash(_sta)]=h_tab[1][hash(_end)]=1,th_tab[0][hash(_sta)]=th_tab[1][hash(_end)]=0;
34 while(!que[0].empty()||!que[1].empty())
35 {
36 int _new;
37 if(!que[0].empty())
38 {
39 _new=move(que[0].front(),'u');
40 if(!h_tab[0][hash(_new)])
41 {
42 h_tab[0][hash(_new)]=1,que[0].push(_new),th_tab[0][hash(_new)]=th_tab[0][hash(que[0].front())]+1;
43 if(h_tab[1][hash(_new)])cout<<th_tab[0][hash(_new)]+th_tab[1][hash(_new)],exit(0);
44 }
45 _new=move(que[0].front(),'d');
46 if(!h_tab[0][hash(_new)])
47 {
48 h_tab[0][hash(_new)]=1,que[0].push(_new),th_tab[0][hash(_new)]=th_tab[0][hash(que[0].front())]+1;
49 if(h_tab[1][hash(_new)])cout<<th_tab[0][hash(_new)]+th_tab[1][hash(_new)],exit(0);
50 }
51 _new=move(que[0].front(),'l');
52 if(!h_tab[0][hash(_new)])
53 {
54 h_tab[0][hash(_new)]=1,que[0].push(_new),th_tab[0][hash(_new)]=th_tab[0][hash(que[0].front())]+1;
55 if(h_tab[1][hash(_new)])cout<<th_tab[0][hash(_new)]+th_tab[1][hash(_new)],exit(0);
56 }
57 _new=move(que[0].front(),'r');
58 if(!h_tab[0][hash(_new)])
59 {
60 h_tab[0][hash(_new)]=1,que[0].push(_new),th_tab[0][hash(_new)]=th_tab[0][hash(que[0].front())]+1;
61 if(h_tab[1][hash(_new)])cout<<th_tab[0][hash(_new)]+th_tab[1][hash(_new)],exit(0);
62 }
63 que[0].pop();
64 }
65 if(!que[1].empty())
66 {
67 _new=move(que[1].front(),'u');
68 if(!h_tab[1][hash(_new)])
69 {
70 h_tab[1][hash(_new)]=1,que[1].push(_new),th_tab[1][hash(_new)]=th_tab[1][hash(que[1].front())]+1;
71 if(h_tab[0][hash(_new)])cout<<th_tab[1][hash(_new)]+th_tab[0][hash(_new)],exit(0);
72 }
73 _new=move(que[1].front(),'d');
74 if(!h_tab[1][hash(_new)])
75 {
76 h_tab[1][hash(_new)]=1,que[1].push(_new),th_tab[1][hash(_new)]=th_tab[1][hash(que[1].front())]+1;
77 if(h_tab[0][hash(_new)])cout<<th_tab[1][hash(_new)]+th_tab[0][hash(_new)],exit(0);
78 }
79 _new=move(que[1].front(),'l');
80 if(!h_tab[1][hash(_new)])
81 {
82 h_tab[1][hash(_new)]=1,que[1].push(_new),th_tab[1][hash(_new)]=th_tab[1][hash(que[1].front())]+1;
83 if(h_tab[0][hash(_new)])cout<<th_tab[1][hash(_new)]+th_tab[0][hash(_new)],exit(0);
84 }
85 _new=move(que[1].front(),'r');
86 if(!h_tab[1][hash(_new)])
87 {
88 h_tab[1][hash(_new)]=1,que[1].push(_new),th_tab[1][hash(_new)]=th_tab[1][hash(que[1].front())]+1;
89 if(h_tab[0][hash(_new)])cout<<th_tab[1][hash(_new)]+th_tab[0][hash(_new)],exit(0);
90 }
91 que[1].pop();
92 }
93 }
94 return 0;
95 }

然后我一条路走到黑,研究起了A*算法……

A*算法我现在研究也不透彻……也是一种广搜,它通过一个估值函数,估算当前扩展出的新状态到目标状态的代价,再选中代价最小的新状态扩展,直到扩展到目标状态……

非常快,速度大概是0~1ms

先转发一个写A*算法很不错的博客:http://www.cnblogs.com/yanlingyin/archive/2012/01/15/2322640.html

再贴个代码:

 1 #include <iostream>
2 #include <deque>
3 #include <algorithm>
4 #include <cstdlib>
5 #define _abs(x) (x>=0?x:-x)//绝对值函数
6 #define h_size 14233333//哈希表大小
7 #define hash(x) (x%h_size)
8 using namespace std;
9 typedef pair<int,int> pii;
10 const int _end=123804765,_enp[2][9]={{1,0,0,0,1,2,2,2,1},{1,0,1,2,2,2,1,0,0}};//end为目标状态,enp[0][i]表示目标状态中数字i所在的行,enp[1][i]表示数字i所在的列
11 int _sta;//开始状态
12 bool _clo[h_size];//a*算法的close表
13 deque<pii> _ol;//a*算法的open表(使用双端队列)
14 int h(int key)//估值函数,使用曼哈顿距离估值
15 {
16 int _map[3][3],_kp[2][9],sum=0;
17 for(int i=2;i>=0;i--)for(int j=2;j>=0;j--)_kp[0][key%10]=i,_kp[1][key%10]=j,key/=10;
18 for(int i=0;i<9;i++)sum+=abs(_kp[0][i]-_enp[0][i])+abs(_kp[1][i]-_enp[1][i]);
19 return sum;
20 }
21 int move(int key,char _ctr)//移动数字0函数,u表示向上,d表示向下,l表示向左,r表示向右
22 {
23 int _kb=key,_map[3][3],i0,j0;
24 for(int i=2;i>=0;i--)for(int j=2;j>=0;j--){_map[i][j]=_kb%10,_kb/=10;if(_map[i][j]==0)i0=i,j0=j;}
25 switch(_ctr)//如果无法扩展(即到达边界)就返回移动前的值
26 {
27 case 'u':if(i0==0)return key;swap(_map[i0][j0],_map[i0-1][j0]);break;
28 case 'd':if(i0==2)return key;swap(_map[i0][j0],_map[i0+1][j0]);break;
29 case 'l':if(j0==0)return key;swap(_map[i0][j0],_map[i0][j0-1]);break;
30 case 'r':if(j0==2)return key;swap(_map[i0][j0],_map[i0][j0+1]);break;
31 }
32 for(int i=0;i<3;i++)for(int j=0;j<3;j++)_kb=_kb*10+_map[i][j];
33 return _kb;
34 }
35 bool cmp(pii a,pii b){return a.second<b.second;}//二分查找比较函数
36 void work(pii _nex)//处理新状态
37 {
38 if(_nex.first==_end)cout<<_nex.second-h(_nex.first),exit(0);//发现正解,直接输出并结束程序
39 if(!_clo[hash(_nex.first)])_ol.insert(lower_bound(_ol.begin(),_ol.end(),_nex,cmp),_nex);//二分查找插入新状态
40 }
41 int main()
42 {
43 cin>>_sta;
44 _ol.push_back(make_pair(_sta,h(_sta)));//把开始状态加入到open表中
45 while(!_ol.empty())//处理open表
46 {
47 pii _now=_ol.front();
48 _ol.pop_front(),_clo[hash(_now.first)]=1;//把当前open表中的最优状态取出并加入到close表中
49 int _nex=move(_now.first,'u');//扩展新状态
50 work(make_pair(_nex,_now.second-h(_now.first)+h(_nex)+1)),_nex=move(_now.first,'d');
51 work(make_pair(_nex,_now.second-h(_now.first)+h(_nex)+1)),_nex=move(_now.first,'l');
52 work(make_pair(_nex,_now.second-h(_now.first)+h(_nex)+1)),_nex=move(_now.first,'r');
53 work(make_pair(_nex,_now.second-h(_now.first)+h(_nex)+1));
54 }
55 return 0;
56 }

八数码难题之 A* 算法的更多相关文章

  1. luogu P1379 八数码难题(A*算法入门详细讲解)

     代码实现细节 #include<cstdio> #include<cstring> #include<iostream> using namespace std; ...

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

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

  3. Codevs 1225 八数码难题

    1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...

  4. [luogu]P1379 八数码难题[广度优先搜索]

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

  5. 洛谷P1379八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...

  6. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

  7. 【洛谷P1379】八数码难题(广搜、A*)

    八数码难题 题目描述 一.广搜: 首先要考虑用什么存每一个状态 显然每个状态都用一个矩阵存是很麻烦的. 我们可以考虑将一个3*3的矩阵用一个字符串或long long 存. 每次扩展时再转化为矩阵. ...

  8. 习题:八数码难题(双向BFS)

    八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...

  9. 「LuoguP1379」 八数码难题(迭代加深

    [P1379]八数码难题 - 洛谷 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种 ...

随机推荐

  1. gRPC入门—golang实现

    1.RPC 1.1 什么是RPC RPC(Remote Procedure Call),即远程过程调用,过程就是方法,简单来说,它就是一种能够像调用本地方法一样调用远程计算机进程中的方法的技术,在这种 ...

  2. js笔记21

    1.解决函数内的this指向 (1)可以在函数外提前声明变量  _this/=this (2)通过apply和call来修改函数内的this指向 二者的区别: 二者的用法不一样,就是参数形式不一样   ...

  3. js笔记15

    DOM2动态创建节点 1.生成节点的方法 document.createElement("div") 2.插入节点的方法 父元素.appendChild(新节点) 在父节点的子节点 ...

  4. 通过RenderDoc真机抓取数据来落地验证和解决特效性能的问题

    前言 需求是来自于我在为我司的一个线上RPG游戏做特效的性能优化的过程中,需要验证对特效的一个改动是否能够提高性能,当然这个改动是在不影响美术效果的前提. 特效性能问题 技能特效 主角的一个大招(技能 ...

  5. 企业如何通过CRM系统使销售周期缩短

    企业为什么要缩短销售周期?因为这意味着可以节约更多开支,从而达到企业利润最大化.但是有不少企业尤其是B2B行业,销售周期都在三个月以上.通过调查发现,很多企业在客户信息和销售管道上缺乏管理和策略.Zo ...

  6. iOS 针对txt文档进行解码

    如我上一篇文章记录,我加了打开其他APPtxt文件的小功能,紧接着碰到新问题了,我在测试过程中发现用户上传的TXT编码格式很多不单单是utf-8和gb2312,针对TXT文档进行解码,我一共经历过两个 ...

  7. 剑指 Offer 12. 矩阵中的路径

    题目描述 是一道很常见的深搜题目,不过里面要考虑一些边界问题,比如走过的路径是不能再次走入的,所以我这里我自己的 代码想到是利用一个新的二维的数组,记录走过的路径,不过题解的直接将原二维数组中的路径隐 ...

  8. Java并发实战一:线程与线程安全

    从零开始创建一家公司 Java并发编程是Java的基础之一,为了能在实践中学习并发编程,我们跟着创建一家公司的旅途,一起来学习Java并发编程. 进程与线程 由于我们的目标是学习并发编程,所以我不会把 ...

  9. 咋滴,不就是面试总考Spring的AOP吗,办它!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 为什么,你的代码总是糊到猪圈上? 怎么办,知道你在互联网,不知道你在哪个大厂.知道你 ...

  10. kong的管理UI选择-konga

    目录 npm方式安装 1. 准备依赖环境 2. 安装konga 3. 配置 4. 环境变量(more) 5. 数据库 配置 初始化/迁移 6. 运行 Docker方式安装 关于Kong-Dashboa ...