Problem DescriptionEight-puzzle, which is also called "Nine grids", comes from an old game. InputThe first line is T (T <= 200), which means the number of test cases of this problem. OutputFor each test case two lines are expected. |
思路分析:
本题中明确说明每个测试样例均有解, 且需计算字典序最小的移动方案, 故适合使用IDA*, 至于估价函数的设计参考本人另外两篇有关八数码问题的博客即可.
//HDOJ3567_Eight II
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;
const int dx[4] = {1, 0, 0, -1}, dy[4] = {0, -1, 1, 0};
const char dir[4] = {'d', 'l', 'r', 'u'};
int ndir[200];//ndir[i]:位置i的反方向
//空格使用数字9表示, tpos[i][0]:tar中数字i所在行, tpos[i][1]:所在列
int tar[4][4], tpos[10][2];//空格使用数字9表示, tpos[i][0]
int beg[4][4];
int maxDeep;
//返回当前beg每个元素与tar中对应相等元素所在位置的曼哈顿距离之和
int F(){
int res = 0;
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j)
if(beg[i][j] != 9){
int t = beg[i][j];
res += abs(i - tpos[t][0]) + abs(j - tpos[t][1]);
}
return res;
}
bool dfs(vector<char> &path){
int f = F(); if(f + path.size() > maxDeep) return false;
if(path.size() == maxDeep) return true;
int x, y;//空格所在位置
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j)
if(beg[i][j] == 9){
x = i, y = j; break;
}
for(int i = 0; i <= 3; ++i){
if(path.size() && path.back() == ndir[dir[i]]) continue;
int a = x + dx[i], b = y + dy[i];
if(a >= 1 && a <= 3 && b >= 1 && b <= 3){
swap(beg[x][y], beg[a][b]), path.push_back(dir[i]);
if(dfs(path)) return true;
swap(beg[x][y], beg[a][b]), path.pop_back();
}
}
return false;
}
int main(){
ndir['u'] = 'd', ndir['d'] = 'u', ndir['l'] = 'r', ndir['r'] = 'l';
int T, sn = 0; scanf("%d", &T);
while(++sn, T--){
char s[100]; scanf("%s", s + 1);
for(int i = 1, k = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j, ++k)
beg[i][j] = s[k] == 'X'? 9: s[k] - '0';
scanf("%s", s + 1);
for(int i = 1, k = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j, ++k){
tar[i][j] = s[k] == 'X'? 9: s[k] - '0';
int t = tar[i][j];
tpos[t][0] = i, tpos[t][1] = j;
}
if(!F()){
cout << "Case " << sn << ": " << 0 << endl;
cout << endl; continue;
}
vector<char> path;
maxDeep = 0; while(++maxDeep, !dfs(path));
cout << "Case " << sn << ": " << path.size() << endl;
for(int i = 0; i < path.size(); ++i) cout << path[i];
cout << endl;
}
return 0;
}