Vijos 八数码问题

背景

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.

描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

格式

输入格式

输入初试状态,一行九个数字,空格用0表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

样例1

样例输入1

283104765

Copy

样例输出1

4

  1 /*
  2     搜索过程没什么好说的
  3     我只想说一下hash
  4     这个判重好坑 数据太细了!
  5     只好用康拓展开
  6 */
  7 #include<cstdio>
  8 #include<cstring>
  9 #include<iostream>
 10 #define MAXN 1000010
 11
 12 using namespace std;
 13
 14 int map[3][3],x,y,head,tail;
 15
 16 int _x[4]={0,1,0,-1};
 17 int _y[4]={1,0,-1,0};
 18
 19 struct node {
 20     int m[3][3];
 21 };
 22 node e[MAXN];
 23
 24 char s[10];
 25
 26 int step[MAXN];
 27
 28 bool _hash[67338000],flag;
 29
 30 inline void _pre() {
 31     string ss="123804765";
 32     for(int i=0;i<9;i++) {
 33         map[x][y]=ss[i]-48;
 34         y++;
 35         if(y==3) x++,y=0;
 36     }
 37     x=0;y=0;
 38     return;
 39 }
 40
 41 inline bool __hash() {
 42     int _Inr=0,k=1,t=1;
 43     for(int i=0;i<3;i++)
 44       for(int j=0;j<3;j++) {
 45           _Inr+=e[tail].m[i][j]*k;
 46           t++,k*=t;
 47       }
 48     //_Inr%=373897779;
 49     if(!_hash[_Inr]) {
 50         _hash[_Inr]=true;
 51         return true;
 52     }
 53     return false;
 54 }
 55
 56 inline bool pd(int i,int j) {
 57     return i>=0&&j>=0&&i<3&&j<3;
 58 }
 59
 60 inline bool check() {
 61     for(int i=0;i<3;i++)
 62       for(int j=0;j<3;j++)
 63         if(e[tail].m[i][j]!=map[i][j]) return false;
 64     return true;
 65 }
 66
 67 inline void move(int p,int q) {
 68     int xx,yy;
 69     for(int i=0;i<4;i++) {
 70         xx=p+_x[i];
 71         yy=q+_y[i];
 72         if(pd(xx,yy)) {
 73             for(int a=0;a<3;a++)
 74               for(int b=0;b<3;b++)
 75                 e[tail].m[a][b]=e[head].m[a][b];
 76             swap(e[tail].m[p][q],e[tail].m[xx][yy]);
 77             step[tail]=step[head]+1;
 78             if(check()) {
 79                 printf("%d\n",step[tail]);
 80                 flag=true;
 81                 return;
 82             }
 83             if(__hash()) tail++;
 84         }
 85     }
 86 }
 87
 88 inline void search() {
 89     while(head<tail) {
 90         for(int i=0;i<3;i++)
 91           for(int j=0;j<3;j++) {
 92               if(e[head].m[i][j]==0) move(i,j);
 93               if(flag) return;
 94           }
 95         head++;
 96     }
 97 }
 98
 99 int main() {
100     _pre();
101     scanf("%s",s);
102     for(int i=0;i<strlen(s);i++) {
103         e[0].m[x][y]=s[i]-48;
104         y++;
105         if(y==3) y=0,x++;
106     }
107     tail++;
108     search();
109     return 0;
110 }

代码

时间: 2024-10-24 02:17:19

Vijos 八数码问题的相关文章

关于八数码问题中的状态判重的三种解决方法(编码、hash、&lt;set&gt;)

八数码问题搜索有很多高效方法:如A*算法.双向广搜等 但在搜索过程中都会遇到同一个问题,那就是判重操作(如果重复就剪枝),如何高效的判重是8数码问题中效率的关键 下面关于几种判重方法进行比较:编码.hash.set 看到问题初学者最先想到的应该就是用一个vis数组标志一下即可.但是该申请多大的数组呢?一个9维数组(9^9=387420489太大了吧)?如果内存允许这是最高效的办法:O(1) 所以我们现在面临的问题是如何在O(1)的时间复杂度不变的情况下把空间压缩下来: 方法一:编码.解码,我们可

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来存储答案.然后就很好写了.