您的位置:首页 > 其它

POJ 1077 - Eight(BFS+康托展开)

2017-12-07 16:46 274 查看
上周作业的ProblemA。从这题难度上就可以看出学长出题时的丧病程度了。(希望他看不到)

有名的八数码题啊,要是没有搞懂康托展开,可以先去百度学习一下再看这道题。

传送门:http://poj.org/problem?id=1077

Eight

Time Limit: 1000MS Memory Limit: 65536K

Total Submissions: 34304 Accepted: 14770 Special Judge

Description

The 15-puzzle has been around for over 100 years; even if you don’t know it by that name, you’ve seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let’s call the missing tile ‘x’; the object of the puzzle is to arrange the tiles so that they are ordered as:

1 2 3 4

5 6 7 8

9 10 11 12

13 14 15 x

where the only legal operation is to exchange ‘x’ with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:

1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8

9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12

13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x

r->           d->           r->


The letters in the previous row indicate which neighbor of the ‘x’ tile is swapped with the ‘x’ tile at each step; legal values are ‘r’,’l’,’u’ and ‘d’, for right, left, up, and down, respectively.

Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and

frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing ‘x’ tile, of course).

In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three

arrangement.

Input

You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus ‘x’. For example, this puzzle

1 2 3

x 4 6

7 5 8

is described by this list:

1 2 3 x 4 6 7 5 8

Output

You will print to standard output either the word “unsolvable”, if the puzzle has no solution, or a string consisting entirely of the letters ‘r’, ‘l’, ‘u’ and ‘d’ that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.

Sample Input

2 3 4 1 5 x 7 6 8

Sample Output

ullddrurdllurdruldr

Source

South Central USA 1998

思路就是,把x视为9或是0,然后将3*3的矩阵拉成一条数列,根据康托展开的原理,每个这样的排列都对应着一个特定的整数,那么这个排列有没有出现过就很容易知道了。由于输入的时候就是一行数列,那么也别费心搞那么麻烦先变3*3又变回来了,直接就保存一行数列,然后保存x的位置就可以了。x在3*3中的位置其实就是x%3, x/3;每次记录好它的康拓展开数,一对比,就出来了。

讲讲这道题的坑点,我一开始老是TLE,以为是算法问题,后面实在找不到了,就把自己的getchar()换成了scanf()结果就过了,这输入数据到底有多少空格啊。。。真是服了

AC代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <string>
#define maxn 10
using namespace std;
int f[maxn] =
{
1,
1,
2,
6,
24,
120,
720,
5040,
40320,
362880
};
//int a[maxn];
//string ans;
int kt(int *t)
{
int su = 0;
for(int i = 0; i < 9; i++)
{
int tmp = 0;
for(int j = 8; j > i; j--)
{
if(t[j] < t[i])
tmp++;
}
su += tmp * f[8-i];
}
return su;
}
int sx, sk;
int rch[800000];
struct Node
{
int x;  //x的位置
int t[maxn];    //每次记录的数组
//  int p;  //字符串的指针
string p;   //答案
int k;  //康托数
};

int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
char di[5] = "udlr";
queue<Node> pa;
int main()
{
char c[20];
//  memset(get, 0, sizeof(get));
int tp = 0;
Node beg;
for(int i = 0; i < 9; i++)
{
scanf("%s", c);
if(c[0] > '0' && c[0] <= '9')
beg.t[tp++] = c[0] - '0';
if(c[0] == 'x')
{
sx = tp;
beg.t[tp++] = 0;
}
}
sk = kt(beg.t);
beg.x = sx, beg.k = sk;
pa.push(beg);
rch[beg.k] = 1;

while(!pa.empty())
{
Node cur = pa.front();
pa.pop();
if(cur.k == 46233)
{
cout << cur.p << endl;
return 0;
}
int a = cur.x / 3;
int b = cur.x % 3;
for(int i = 0; i < 4; i++)
{
int ta = a + dx[i];
int tb = b + dy[i];
if(ta < 0 || ta > 2 || tb < 0 || tb > 2)    continue;

Node next = cur;
next.x = 3 * ta + tb;
next.t[cur.x] = next.t[next.x];
next.t[next.x] = 0;
next.k = kt(next.t);
if(rch[next.k])    continue;
if(next.k == 46233)
{
next.p = cur.p + di[i];
cout << next.p << endl;
return 0;
}

next.p = cur.p + di[i];
rch[next.k] = 1;
pa.push(next);
}
}
printf("unsolvable\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: