codevs1225 八数码难题

题目描述 Description

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

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

283104765

样例输出 Sample Output

4

正解:BFS+hash

解题报告:

  向总让我写标程,然后我就愉快地开始写这道最初学搜索时的水题,然而我第一遍wa了,mdzz

  hash判重,BFS搜索
 
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <algorithm>
 7 using namespace std;
 8 typedef long long LL;
 9 const int MOD = 1000007;//hash的模
10 char ch[12];
11 int now;
12 int a[100001][10];//记录状态
13 int times[100001];//计算移动次数
14 int final[10]={1,2,3,8,0,4,7,6,5};//目标局面
15 int cnt,hash[1000008],next[100001],to[100001];//hash表
16 
17 void insert(int x){//插入哈希表
18     int num=0;
19     for(int i=0;i<9;i++) num=num*9+a[x][i];
20     int ha=num%MOD;
21     next[++cnt]=hash[ha]; hash[ha]=cnt; to[cnt]=num;
22 }
23 
24 bool check(int x){//哈希判重,挂链
25     int num=0;
26     for(int i=0;i<9;i++) num=num*9+a[x][i];
27     int ha=num%MOD;
28     for(int i=hash[ha];i;i=next[i]) 
29     if(to[i]==num) return false;
30     return true;
31 }
32 
33 int main()
34 {
35   for(int i=0;i<9;i++) ch[i]=getchar();
36   for(int i=0;i<9;i++) a[1][i]=ch[i]-'0';
37   int head=0,tail=1; insert(1);
38   while(head<tail) {
39       head++;
40       for(int i=0;i<9;i++) if(a[head][i]==0) { now=i; break; }//找到当前0的位置
41       for(int k=-3;k<=3;k+=2) {//枚举移动的每一种可能
42       int to=now+k;
43       if(to<0 || to>=9) continue;//越界
44       if(now%3==2 && k==1) continue;//在右边界上不能再向右移动一格
45       if(now%3==0 && k==-1) continue;//在左边界不能再向左移动一格
46       tail++;  for(int i=0;i<9;i++) a[tail][i]=a[head][i];//把交换前的情况复制到新数组
47       swap(a[tail][now],a[tail][to]);//交换位置
48       if(check(tail)) {//得到一组可行解
49           times[tail]=times[head]+1;
50           bool ok=true;
51           for(int i=0;i<9;i++) if(a[tail][i]!=final[i]) { ok=false; break; }
52           if(ok) { printf("%d",times[tail]); return 0; }
53           insert(tail);     
54       }
55       else tail--;//此状态已经重复,可以省略
56       }
57   }
58   return 0;
59 }
原文地址:https://www.cnblogs.com/ljh2000-jump/p/5677133.html