題目:計算一個八數碼狀態對應的最遠狀態,即需要移動最多步數的狀態。
分析:圖論,搜索。根據0的位置不同分為9類情況,打表計算每個類別的情況即可。
如果0初始的位置相同則狀態為同一類別,只是位置編號不同;
利用bfs計算9種狀態(0的位置不同)對應的最遠距離,存儲結果;
(這裡就是普通的八數碼算法,bfs+康拓展開)
對於每組輸入判斷輸入那個類別,然後對位置做映射即可。
說明:移動的任意一組解都可以,還有一道╮(╯▽╰)╭。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int output_block[9][9];
char output_step[9][100];
int puzzle[9][9] = {
0, 1, 2, 3, 4, 5, 6, 7, 8,
1, 0, 2, 3, 4, 5, 6, 7, 8,
1, 2, 0, 3, 4, 5, 6, 7, 8,
1, 2, 3, 0, 4, 5, 6, 7, 8,
1, 2, 3, 4, 0, 5, 6, 7, 8,
1, 2, 3, 4, 5, 0, 6, 7, 8,
1, 2, 3, 4, 5, 6, 0, 7, 8,
1, 2, 3, 4, 5, 6, 7, 0, 8,
1, 2, 3, 4, 5, 6, 7, 8, 0,
};
// cantor_expansion_define
int factorial[9] = {0, 1, 2, 6, 24, 120, 720, 5040, 40320};
int cantor(int block[9])
{
int value = 0;
for (int i = 0; i < 9; ++ i) {
int count = 0;
for (int j = 0; j < i; ++ j) {
if (block[j] > block[i]) {
count ++;
}
}
value = value + count*factorial[i];
}
return value;
}
// cantor_expansion_define_over
// judge_function_define
int can_left(int value)
{
if (value%3 != 0) {
return value-1;
}else {
return -1;
}
}
int can_right(int value)
{
if (value%3 != 2) {
return value+1;
}else {
return -1;
}
}
int can_up(int value)
{
if (value/3 != 0) {
return value-3;
}else {
return -1;
}
}
int can_down(int value)
{
if (value/3 != 2) {
return value+3;
}else {
return -1;
}
}
int (*function[])(int value) = {can_up, can_left, can_down, can_right};
// judge_function_define_over
int state(int block[9])
{
int value = 0;
for (int i = 0; i < 9; ++ i) {
value = value*9 + block[i];
}
return value;
}
int unstate(int value, int block[9])
{
int zero_position = 0;
for (int i = 8; i >= 0; -- i) {
block[i] = value%9;
value /= 9;
if (block[i] == 0) {
zero_position = i;
}
}
return zero_position;
}
char action[4] = {'U', 'L', 'D', 'R'};
char steps[3628800];
int front[3628800];
int visit[3628800];
int queue[3628800];
int bfs(int input[9], int out_value[9], char out_step[])
{
int block[9];
for (int i = 0; i < 9; ++ i) {
block[i] = input[i];
}
memset(visit, 0, sizeof(visit));
int cantor_value = cantor(block);
int state_value = state(block);
visit[cantor_value] = 1;
int move = 0, save = 0;
steps[save] = '#';
queue[save ++] = state_value;
while (move < save) {
int now = queue[move ++];
int now_zero = unstate(now, block);
for (int i = 0; i < 4; ++ i) {
int new_zero = function[i](now_zero);
if (new_zero != -1) {
swap(block[now_zero], block[new_zero]);
cantor_value = cantor(block);
state_value = state(block);
if (!visit[cantor_value]) {
visit[cantor_value] = 1;
steps[save] = action[i];
front[save] = move-1;
queue[save ++] = state_value;
}
swap(block[now_zero], block[new_zero]);
}
}
}
unstate(queue[move-1], block);
for (int i = 0; i < 3; ++ i) {
for (int j = 0; j < 3; ++ j) {
out_value[3*i+j] = block[3*i+j];
}
}
int step_count = 0, now_place = move-1;
while (steps[now_place] != '#') {
out_step[step_count ++] = steps[now_place];
now_place = front[now_place];
}
int left = 0, right = step_count-1;
while (left < right) {
swap(out_step[left], out_step[right]);
left ++;
right --;
}
}
int main()
{
// make list for 9 states
for (int i = 0; i < 9; ++ i) {
bfs(puzzle[i], output_block[i], output_step[i]);
}
int n;
int input[9];
int output[9];
while (~scanf("%d",&n)) {
for (int t = 1; t <= n; ++ t) {
int index = 0;
for (int i = 0; i < 9; ++ i) {
scanf("%d",&input[i]);
if (input[i] == 0) {
index = i;
}
}
for (int i = 0; i < 9; ++ i) {
for (int j = 0; j < 9; ++ j) {
if (puzzle[index][j] == output_block[index][i]) {
output[i] = input[j];
break;
}
}
}
printf("Puzzle #%d\n",t);
for (int i = 0; i < 3; ++ i) {
for (int j = 0; j < 3; ++ j) {
printf("%d",output[3*i+j]);
if (j != 2) {
printf(" ");
}else {
printf("\n");
}
}
}
printf("%s\n\n",output_step[index]);
}
}
return 0;
}