Constraints
Time Limit: 2 secs, Memory Limit: 256 MB
Description
Nine tiles, each with a number from 1 to 9 on it, are packed into a 3 by 3 frame. Your task is to arrange the tiles so that they are ordered as:
1 2 3
4 5 6
7 8 9
At each step, you can do the following operation to the tiles: Choose 2 by 2 tiles, rotate the tiles in clockwise order. For example:
1 2 3 4 1 3 1 2 3 1 2 3
4 5 6 => 5 2 6 or 4 5 6 => 4 8 5
7 8 9 7 8 9 7 8 9 7 9 6
Write a program to find the minimum number of steps.
Input
Input contains multiple test cases.
Each test case is a description of a configuration of the nine tiles. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and from left to right within a row, where the tiles are represented by numbers 1 to 9. For example:
9 8 7
6 5 4
3 2 1
is described by this list:
9 8 7 6 5 4 3 2 1
Output
Output the minimum number of steps on a single line for each test case.
Sample Input
1 2 3 4 5 6 7 8 9 4 1 3 5 2 6 7 8 9
Sample Output
0 3
Problem Source
每周一赛:2010中山大学新手赛
Solution:
这是一道隐式图搜索,每一个状态就是一个节点,最短路用宽度优先搜索就ok啦~
另外就是状态编码使用康托展开,节省空间和运算量,但是其实用map来实现字符串编码也是ok的
注意的一点就是,这道题目的话可以用逆向思维做才不会超时,因为终点都是一样的,那么只需要从终点出发,逆向遍历所有节点一遍,并且保存最短路径的长度即可。
逆向遍历的时候操作要从顺时针变成逆时针~
#include <iostream>
#include <queue>
#include <cstring>
#define AIM 123456789
using namespace std;
int t[3][3], p[] = {0, 1, 3, 4}, ans[370000];
int fator[] = {0, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
int operate(int x, int op)
{
int i, j, temp, ans = 0;
for (i = 2; i >= 0; -- i)
for (j = 2; j >= 0; -- j)
{
t[i][j] = x % 10;
x /= 10;
}
i = op / 3;
j = op % 3;
temp = t[i][j];
t[i][j] = t[i][j+1];
t[i][j+1] = t[i+1][j+1];
t[i+1][j+1] = t[i+1][j];
t[i+1][j] = temp;
for (i = 0; i < 3; ++ i)
for (j = 0; j < 3; ++ j)
{
ans *= 10;
ans += t[i][j];
}
return ans;
}
int encode(int x)//康托展开
{
int i, t[10], code;
i = code = 0;
while (x)
{
t[++i] = x % 10;
x /= 10;
}
for (i = 9; i >= 1; --i)
{
int temp = 0;
for (int j = i-1; j >= 1; --j) if (t[i] > t[j]) ++temp;
code += fator[i-1] * temp;
}
return code;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int i, j;
memset(ans, -1, sizeof(ans));
queue<int> q;
q.push(123456789);
ans[0] = 0;
while (!q.empty())//BFS
{
int temp = q.front();
q.pop();
int t_c = encode(temp);
for (i = 0; i < 4; ++ i)
{
int next = operate(temp, p[i]);
int n_c = encode(next);
if (ans[n_c] == -1)
{
ans[n_c] = ans[t_c] + 1;
q.push(next);
}
}
}
while (cin >> t[0][0])
{
int initial = t[0][0];
for (i = 0; i < 3; ++ i)
for (j = 0; j < 3; ++ j)
{
if (i == 0 && j == 0) continue;
cin >> t[i][j];
initial *= 10;
initial += t[i][j];
}
cout << ans[encode(initial)] << '\n';
}
return 0;
}