码迷,mamicode.com
首页 > 其他好文 > 详细

Aizu 0121 Seven Puzzle (康托展开+bfs)

时间:2015-03-31 23:53:17      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:

Seven Puzzle

Time Limit : 1 sec, Memory Limit : 65536 KB

7パズルは8つの正方形のカードとこれらのカードがぴたりと収まる枠を使って行います。それぞれのカードは互いに区別できるように、0,1,2....7と番号がつけられています。枠には、縦に2個、横に4個のカードを並べることができます。

7パズルを始めるときには、まず枠にすべてのカードを入れます。枠のなかで0のカードだけは、上下左右に隣接するカードと位置を交換することができます。たとえば、枠の状態が図( a )のときに、0のカードの右に隣接した、7のカードと位置を交換すれば、図( b )の状態になります。あるいは、図( a )の状態から0のカードの下に隣接した2のカードと位置を交換すれば図( c )の状態になります。カードの位置を入れ替える操作はこれだけが許されます。図( a )の状態で0のカードと上下左右に隣接するカードは7と2のカードだけなので、これ以外の位置の入れ替えは許されません。

ゲームの目的は、カードをきれいに整列して図( d )の状態にすることです。最初の状態を入力とし、カードをきれいに整列するまでに、必要な最小手数を出力して終了するプログラムを作成してください。ただし、入力されたカードの状態からは図( d )の状態に移ることは可能であるとします。

入力データは、1行に8つの数字が与えられます。これらは、最初の状態のカードの並びを表します。図( a )の数字表現は0,7,3,4,2,5,1,6に、図( c )は2,7,3,4,0,5,1,6となります。

技术分享 技术分享
図( a ) 0,7,3,4,2,5,1,6の場合図( b ) 7,0,3,4,2,5,1,6の場合


技术分享 技术分享
図( c ) 2,7,3,4,0,5,1,6の場合図( d ) 0,1,2,3,4,5,6,7(最終状態)

Input

1つ目のパズルの状態(整数;空白区切り)
2つ目のパズルの状態(整数;空白区切り)
     :
     :

与えられるパズルの数は1000以下です。

Output

1つ目のパズルの状態から最終状態へ移行する最小手数(整数)
2つ目のパズルの状態から最終状態へ移行する最小手数(整数)
            :
            :

Sample Input

0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0

Output for the Sample Input

0
1
28

题意:
给个初始状态为0-7的一个排列,0表示空格。可以挪动空格周围的数字,最后使得最终状态为0-7顺序排列。

分析:
就是类似八数码的问题。之前没做过八数码的题。

记录下思考过程。
首先很容易想到就是从初始状态开始搜索出最终状态,每次的策略就是移动0周围的
数字。但,怎么表示状态呢?这8个格子不是可以看成矩阵用二维数组记录吗?于是。。。

1、可以用一个结构体,结构体中有一个二维数组来记录,另一个变量记录初始状态搜到的步数
2、结构体中的数组可以用一维数组,这样策略就是0所在的位置p与p+1、p-1、p+4、p-4四个位置
的元素交换,当然交换的pos位置必须在0-7范围内,且 换行的地方要注意!!!
p=3时,pos=4是不行的
p=4时,pos=3是不行的

然后就是bfs搜了。
状态有8!(8个数全排列)= 40320

开始用的sum(a[i]*i)来hash,总是从7 6 5 4 3 2 1 0搜不到目标状态。
后来意识到是hash的时候有重复造成的错误!

于是看了下康托展开:http://zh.wikipedia.org/wiki/%E5%BA%B7%E6%89%98%E5%B1%95%E5%BC%80
康托展开是一个全排列到一个自然数双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。

于是改写了hash方法后,能过样例了。。。
但是tle
于是把之前所有用vector的地方都改成了手写数组int a[8]。。
还是tle

于是想到预处理,从0 1 2 3 4 5 6 7这个排列作初始状态出发来搜,
hash[i]记录到达i对应的排列的步数
n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。
所以hash数组只要开8!+1=40321即可!
OK!

技术分享
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdlib>
  6 #include<cmath>
  7 #include<vector>
  8 #include<queue>
  9 #include<map>
 10 #include<set>
 11 
 12 using namespace std;
 13 
 14 typedef long long ll;
 15 
 16 struct node
 17 {
 18     int sta[8];
 19     int step;
 20     int p;
 21 };
 22 queue<node> q;
 23 int s[8];
 24 
 25 int d[] = {-4,-1,1,4};
 26 int hash[40321];
 27 int w[10],vec[10];
 28 
 29 void init()
 30 {
 31     w[0] = 1;
 32     int sum = 1;
 33     for(int i=1;i<=7;i++)
 34     {
 35         sum*=i;
 36         w[i] = sum;
 37     }
 38 }
 39 
 40 void solve()
 41 {
 42     while(!q.empty()) q.pop();
 43     memset(hash,-1,sizeof(hash));
 44 
 45     node ff,gg,hh;
 46     for(int i=0;i<8;i++)
 47         ff.sta[i] = i;
 48     ff.step = 0;
 49 
 50 
 51     int mark = 0,pos;
 52     int n = 8;
 53     for(int i=0;i<n;i++)
 54     {
 55         int cnt = 0;
 56         for(int j=i+1;j<n;j++)
 57         {
 58             if(s[j]<s[i]) cnt++;
 59         }
 60         vec[n-i-1] = cnt;
 61     }
 62     for(int i=0;i<n;i++)
 63         mark += vec[i]*w[i];
 64     mark++;
 65     ff.p = mark;
 66     q.push(ff);
 67     hash[mark] = 0;
 68 
 69     int cur[8],next[8];
 70     while(!q.empty())
 71     {
 72         gg = q.front();
 73         q.pop();
 74         memcpy(cur,gg.sta,sizeof(gg.sta));
 75         int step = gg.step;
 76 
 77         for(int i=0;i<8;i++)
 78         {
 79             if(cur[i] == 0)
 80             {
 81                 pos = i;
 82                 break;
 83             }
 84         }
 85 
 86         for(int i=0;i<4;i++)
 87         {
 88             int x = pos+d[i];
 89             if(x<0 || x>7) continue;
 90             if(x==3 && pos==4) continue;
 91             if(x==4 && pos==3) continue;
 92 
 93             memcpy(next,cur,sizeof(cur));
 94 
 95             int tmp = next[x];
 96             next[x] = next[pos];
 97             next[pos] = tmp;
 98 
 99             int mark = 0;
100             for(int k=0;k<8;k++)
101             {
102                 int cnt = 0;
103                 for(int j=k+1;j<8;j++)
104                 {
105                     if(next[j]<next[k]) cnt++;
106                 }
107                 vec[n-k-1] = cnt;
108             }
109             for(int k=0;k<8;k++)
110                 mark += vec[k]*w[k];
111             mark++;
112             if(hash[mark]!=-1) continue;
113 
114             memcpy(hh.sta,next,sizeof(next));
115             hh.step = step+1;
116             hh.p = mark;
117             q.push(hh);
118             hash[mark] = hh.step;
119         }
120     }
121 }
122 
123 int main()
124 {
125    // freopen("1.txt","w",stdout);
126 
127     init();
128     solve();
129     int x;
130     while(~scanf("%d",&s[0]))
131     {
132         for(int i=1;i<=7;i++)
133         {
134             scanf("%d",&x);
135             s[i] = x;
136         }
137         int omg = 0;
138         for(int i=0;i<8;i++)
139         {
140             int cnt = 0;
141             for(int j=i+1;j<8;j++)
142             {
143                 if(s[j]<s[i])
144                     cnt++;
145             }
146             vec[8-1-i] = cnt;
147         }
148         for(int i=0;i<8;i++)
149             omg += vec[i]*w[i];
150         omg++;
151         printf("%d\n",hash[omg]);
152     }
153     return 0;
154 }
View Code

 








 

Aizu 0121 Seven Puzzle (康托展开+bfs)

标签:

原文地址:http://www.cnblogs.com/hadis-yuki/p/4382209.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!