Vijos 八数码问题

背景

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

描述

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

格式

输入格式

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

输出格式

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

样例1

样例输入1

283104765

样例输出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 }
代码

 

posted @ 2017-07-05 21:44  拿叉插猹哈  阅读(132)  评论(0编辑  收藏  举报