Problem Specification Value
Time Limit 10 Sec
Memory Limit 162 MB
Submit 1558
Solved 858

Description

在一个 5×5 的棋盘上有 12 个白色的骑士和 12 个黑色的骑士, 且有一个空位. 在任何时候一个骑士都能按照骑士的走法 (它可以走到和它横坐标相差为 1, 纵坐标相差为 2 或者横坐标相差为 2, 纵坐标相差为 1 的格子) 移动到空位上. 给定一个初始的棋盘, 怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神, 他们必须以最少的步数完成任务.

Input

第一行有一个正整数 T (T<=10), 表示一共有 N 组数据. 接下来有 T 个 5×5 的矩阵, 0 表示白色骑士, 1 表示黑色骑士, * 表示空位. 两组数据之间没有空行.

Output

对于每组数据都输出一行. 如果能在 15 步以内 (包括 15 步) 到达目标状态, 则输出步数, 否则输出- 1.

Sample Input

2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100

Sample Output

7
-1

HINT

Source


搜索+剪枝, 剪枝函数定义为不在该在的位置上的骑士的个数.



#include <iostream>
#include <cstdlib>
#include <cstdio>

using namespace std;

int targ_ans[5][5] = {
    {1, 1, 1, 1, 1},
    {0, 1, 1, 1, 1},
    {0, 0, 2, 1, 1},
    {0, 0, 0, 0, 1},
    {0, 0, 0, 0, 0}
};
// Available move sequences
int mov_x[8] = {1,  1,  -1, -1, 2,  2,  -2, -2},
    mov_y[8] = {2,  -2, 2,  -2, 1,  -1, 1,  -1};
bool complete;
int t, res;

// Judge whether this is the final answer, arr[][] represents the colours of the
// pawns, (emp_x, emp_y) represents the coords of the empty position.
bool judge(int arr[5][5], int emp_x, int emp_y)
{
    if (emp_x != 2 || emp_y != 2)
        return false;
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++)
            if (arr[i][j] != targ_ans[i][j])
                return false;
    return true;
}

// Cost of further iteration, as in IDA*.
int evaluate(int depth, int step, int arr[5][5])
{
    int req = 0;
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++)
            if (arr[i][j] != targ_ans[i][j]) {
                req++;
                if (req + step > depth)
                    return 0;
            }
    return 1;
}

// Search with step #step, in checkerboard arr[][], with (x, y) as the coords of
// the empty position. depth is the largest depth of iteration.
void search(int depth, int step, int arr[5][5], int x, int y)
{ // Unoptimized brute force search.
    // Termination arguments.
    // printf("search %d %d %d %d\n", depth, step, x, y);
    if (step == depth) {
        if (judge(arr, x, y))
            complete = true;
        return ;
    }
    if (complete)
        return ;
    // Iterate reversely, whether this poses potential for another pawn to move
    // to the empty space hither.
    for (int i = 0; i < 8; i++) {
        int newx = x + mov_x[i],
            newy = y + mov_y[i];
        if (newx < 0 || newx > 4 || newy < 0 || newy > 4)
            continue;
        swap(arr[x][y], arr[newx][newy]);
        if (evaluate(depth, step, arr))
            search(depth, step + 1, arr, newx, newy);
        swap(arr[x][y], arr[newx][newy]);
    }
    return ;
}

int main(int argc, char** argv)
{
    scanf("%d", &t);
    for (int idx = 1; idx <= t; idx++) {
        int arr[5][5];
        int emp_x, emp_y; // The coords of the blank grid position
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++) {
                char ch = ' ';
                while (ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n')
                    scanf("%c", &ch);
                if (ch == '0') arr[i][j] = 0;
                else if (ch == '1') arr[i][j] = 1;
                else arr[i][j] = 2, emp_x = i, emp_y = j;
            }
        // Done readin, searching.
        res = -1;
        complete = false;
        for (int k = 1; k <= 15; k++) {
            // Search and iterate with depth of k.
            search(k, 0, arr, emp_x, emp_y);
            if (complete) {
                res = k;
                break;
            }
        }
        // Outputting data.
        printf("%d\n", res);
    }
    return 0;
}