6-23 重排n²宫问题
问题描述
重排九宫是一个古老的单人智力游戏。据说重排九宫起源于我国古时由三国演义故事“关羽义释曹操”而设计的智力玩具“华容道”,后来流传到欧洲,将人物变成数字。原始 的重排九宫问题是这样的:将数字 1~8 按照任意次序排在 3×3 3 × 3 的方格阵列中,留下一个空格。与空格相邻的数字,允许从上,下,左,右方向移动到空格中。游戏的最终目标是通过 合法移动,将数字 1~8 按行排好序。在一般情况下,重排 n2 宫问题是将数字 1~ n2−1 n 2 − 1 按照 任意次序排在 n×n n × n 的方格阵列中,留下一个空格。允许与空格相邻的数字从上,下,左,右 4 个方向移动到空格中。游戏的最终目标是通过合法移动,将初始状态变换到目标状态。
对于给定的 n×n n × n 方格阵列中数字 1~ n2−1 n 2 − 1 初始排列和目标状态,编程计算将初始排列通 过合法移动变换为目标状态最少移动次数。
数据输入:
第 1 行有 1 个正整数 n。以下的 n 行是
n×n
n
×
n
方格 阵列的中数字 1~
n2−1
n
2
−
1
的初始排列,每行有 n 个数字表示该行方格中的数字, 0 表示空格。 接着的 n 行是方格阵列中数字 1~
n2−1
n
2
−
1
的目标状态。
Java
package Chapter6FenZhiXianJieFa;
import java.util.Collections;
import java.util.Scanner;
import java.util.Vector;
public class ChongPaiNxNGong {
private static class Board{
int y,x; //空格位置
Vector<Integer> path;
int dist; //manhattan距离
Vector<Integer> boardm;
private int heur(){
return dist;
}
private void getboard(int[] m){
for(int i=0; i<boardsz; i++){
boardm.add(m[i]);
if(m[i] == 0) {y=i/rowsz; x=i%rowsz;}
}
dist=0;
for(int i=0; i<boardsz; i++)
if(boardm.get(i) != 0) dist+=getdist(boardm.get(i),i);
}
//按3个方向移动
private boolean move(int dir){
final int[][] step = {{0,-1},{0,1},{-1,0},{1,0}};//空格移动方向: 上 下 左 右//dir: 0 1 2 3
int nx = x+step[dir][0];
int ny = y+step[dir][1];
if((path.isEmpty()||op[dir]!=(path.lastElement())) && nx>-1 && nx<rowsz && ny>-1 && ny<rowsz){
dist = dist+1-getdist(boardm.get(ny*rowsz+nx),ny*rowsz+nx)+getdist(boardm.get(ny*rowsz+nx),y*rowsz+x);
Collections.swap(boardm,y*rowsz+x,ny*rowsz+nx);
y=ny; x=nx;
path.add(dir);
return true;
}else
return false;
}
//计算manhattan距离
private int getdist(int v, int loc){
int dis = Math.abs((pos[v]%rowsz)-(loc%rowsz));
dis += Math.abs((pos[v]/rowsz)-(loc/rowsz));
return dis;
}
//到达目标状态
private boolean reached(){
for(int i=0; i<boardsz; i++)
if(boardm.get(i) != dest[i]) return false;
return true;
}
private void out(){
char[] dir = {'U','D','L','R'};//空格移动方向: 上 下 左 右//dir: 0 1 2 3
System.out.println(path.size());
for(int i=0; i<path.size(); i++){
System.out.print(dir[path.get(i)]);
if(i%20 == 19) System.out.println();
}
if(path.size()%20 != 0) System.out.println();
}
}
private static final int[] op = {1,0,3,2};
private static int maxdep;
private static int rowsz,boardsz;
private static int[] sour,dest,pos;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
init(input);
if(odd()) idastar();
else System.out.println("No Solution!");
}
}
private static void init(Scanner input){
rowsz = input.nextInt();
boardsz = rowsz*rowsz;
sour = new int[boardsz];
dest = new int[boardsz];
pos = new int[boardsz];
for(int i=0; i<boardsz; i++)
sour[i] = input.nextInt();
for(int i=0; i<boardsz; i++){
dest[i] = input.nextInt();
pos[dest[i]] = i;
}
}
private static boolean odd(){
int[] c = new int[boardsz];
int count=0,count1=0,i1=0,j1=0,i2=0,j2=0;
for(int k=0; k<boardsz; k++){
c[dest[k]] = sour[k];
if(sour[k] == 0) {i1=k/rowsz+1; j1=k%rowsz+1;}
if(dest[k] == 0) {i2=k/rowsz+1; j2=k%rowsz+1;}
}
int posi = ((i1+i2)%2+(j1+j2)%2)%2;
for(int j=0; j<boardsz; j++){
int k=c[j],k1=j;
count1 = 0;
while (k >= 0) {k=c[k1]; c[k1]=-1; k1=k; count1++;}
if(count1 > 0) count+=count1-2;
}
if(count%2 == posi) return true;
else return false;
}
private static boolean solve(int dep, Board E){
if(dep+E.dist <= maxdep){
if(E.reached()) {E.out(); return true;}
for(int i=0; i<4; i++){
// Board N = E;
Board N = new Board();
N.x = E.x;
N.y = E.y;
N.dist = E.dist;
N.boardm = new Vector<>();
N.path = new Vector<>();
N.boardm = (Vector)E.boardm.clone();
N.path = (Vector)E.path.clone();
if(N.move(i))
if(solve(dep+1,N))
return true;
}
}
return false;
}
//IDA*算法
private static void idastar(){
Board E = new Board();
E.boardm = new Vector<>();
E.path = new Vector<>();
E.getboard(sour);
maxdep = E.heur();
if(maxdep == 0){
System.out.println(0);
return;
}
while (!solve(0,E))
maxdep += 2;
}
}
Input & Output
3
1 2 3
4 0 6
7 5 8
1 2 3
4 5 6
7 8 0
2
DR
3
1 2 3
4 0 6
7 5 8
1 2 3
4 5 6
7 8 0
2
DR
3
6 7 3
2 5 1
8 4 0
1 2 3
4 5 6
7 8 0
26
ULULDRURDDLURDLLURRU
LLDRRD
3
7 2 8
5 4 3
6 0 1
1 2 3
4 5 6
7 8 0
No Solution!
3
7 0 3
8 1 2
6 5 4
1 2 3
4 5 6
7 8 0
17
DRDLLUURDRDLLURRD
Reference
王晓东《计算机算法设计与分析》