您的位置:首页 > 其它

hdu 1043 Eight

2015-02-19 15:36 351 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

题目大意:给出魔方现在的状态:

2 3 4 1 5 x 7 6 8 -> 

2 3 4

1 5 x

7 6 8

要求的魔方目的状态:

1 2 3

4 5 6

7 8 x

其中有4中操作:

(1) 2 3 4........2 3 x

......1 5 x...u->.1 5 4

......7 6 8........7 6 8

(2) 2 3 x........2 x 3

......1 5 4...l->.1 5 4

......7 6 8........7 6 8

(3) x 2 3........1 2 3

......1 5 4...d->.x 5 4

......7 6 8........7 6 8

(4) 1 2 3........1 2 3

......7 5 4...r->.7 5 4

......x 6 8........6 x 8

题目分析:反向搜索,从目标状态找回状态对应,将能到达的所有状态的路径保存下来,状态的表示用康托展开。

康托展开:X = an*(n-1)! + an-1*(n-2)! + …… + ai*(i-1)! + …… + a2*1! + a1*0!

其中ai表示比第i个数小的数字的个数(并且在前面没有出现过)

康托展开中排列中的数字没有重复的

例如:3 5 7 4 1 2 9 6 8(共9位数)

比3小的数都没有出现过,所以共有2个,以这样的数开始的排列有(9-1)!个,因此第一项为2 * 8!

比5小的数3出现过,所以共有3个,以这样的数开始的排列有(9-2)!个,因此第一项为3 * 7!

……

比8小的数都出现过,所以共有0个,以这样的数开始的排列有(9-9)!个,因此第一项为0
* 0!

所以,康托展开就为:X = 2 * 8! + 3 * 7! + 4 * 6! + 2 * 5! + 0 * 4! + 0 * 3! + 2 * 2! + 0 * 1! + 0 * 0! = 98884.

代码参考:

#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e6 + 9; //最多是9!/2
const int AIM = 46234; //12345670对应的康托展开的hash值

int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; //康拖展开判重
//           0! 1! 2! 3! 4!  5!   6!   7!    8!     9!
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
char indexs[5]="durl";//和上面的要相反,因为是反向搜索
bool vis
; //标记
string path
; //记录路径

struct Node
{
int s[9];
int id, hashVal;
string path; //路径
}puzzle;
queue<Node> q;

int cantor(int s[]) //康拖展开求该序列的hash值
{
int sum = 0;
for(int i = 0; i < 9; ++ i) {
int num = 0;
for(int j = i + 1; j < 9; ++ j) {
if(s[j] < s[i]) num ++;
}
sum += (num * fac[9 - i - 1]);
}
return sum + 1;
}

void bfs(Node s)
{
q.push(s);
path[AIM] = "";
while(!q.empty()) {
Node head = q.front();
q.pop();
for(int i = 0; i < 4; ++ i) {
int x = head.id / 3 + dir[i][0];
int y = head.id % 3 + dir[i][1];
if(x < 0 || x >= 3 || y < 0 || y >= 3) continue;
Node t = head;
t.id = x * 3 + y;
t.s[head.id] = t.s[t.id];
t.s[t.id] = 0;
t.hashVal = cantor(t.s);
if(!vis[t.hashVal]) {
vis[t.hashVal] = 1; //此状态可达
t.path = indexs[i] + t.path; //因为是逆序,当前这步+之前的路径
q.push(t);
path[t.hashVal] = t.path;
}
}
}
}

int main()
{
char ch;
Node start; //起点即为目标序列
for(int i = 0; i < 8; ++ i) {
start.s[i] = i + 1;
}
start.s[8] = 0;
start.id = 8;
start.hashVal = AIM;
start.path = "";
bfs(start);
while(cin >> ch) {
if(ch == 'x') {
puzzle.s[0] = 0;
puzzle.id = 0;
} else {
puzzle.s[0] = ch - '0';
}
for(int i = 1; i < 9; ++ i) {
cin >> ch;
if(ch == 'x') {
puzzle.s[i] = 0;
puzzle.id = i;
}
else puzzle.s[i] = ch - '0';
}
puzzle.hashVal = cantor(puzzle.s); //获取输入序列的hash值
if(vis[puzzle.hashVal]) {
cout<<path[puzzle.hashVal]<<endl;
} else {
puts("unsolvable");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  搜索 hash path