演算法設計與分析: 5-37 n²-1謎問題
阿新 • • 發佈:2019-01-23
5-37 n²-1謎問題
問題描述
重排九宮是一個古老的單人智力遊戲。據說重排九宮起源於我國古時由三國演義故事“關羽義釋曹操”而設計的智力玩具“華容道”,後來流傳到歐洲,將人物變成數字。原始 的重排九宮問題是這樣的:將數字 1~8 按照任意次序排在 的方格陣列中,留下一個空 格。與空格相鄰的數字,允許從上,下,左,右方向移動到空格中。遊戲的最終目標是通過 合法移動,將數字 1~8 按行排好序。在一般情況下,謎問題是將數字 1 ~ 按照任意次序排在 的方格陣列中,留下一個空格。允許與空格相鄰的數字從上,下,左,右 4 個方向移動到空格中。遊戲的最終目標是通過合法移動,將初始狀態變換到目標狀態。 謎問題的目標狀態是將數字 1~按從小到大的次序排列,最後一個位置為空格。
對於給定的 方格陣列中數字 1~ 初始排列,程式設計計算將初始排列通過合法移動 變換為目標狀態最少移動次數。
資料輸入:
第 1 行有 1 個正整數 n。以下的 n 行是 方格 陣列的中數字 1~ 的初始排列,每行有 n 個數字表示該行方格中的數字, 0 表示空格。
Java
package Chapter5HuiSuFa;
import java.util.Scanner;
public class NxN_1Mi {
private static int rowsz,boardsz;
private static int[] start,board;
private static int moves;
private static int[] pos;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
rowsz = input.nextInt();
boardsz = rowsz*rowsz;
start = new int[boardsz];
board = new int[boardsz];
pos = new int[100];
int del = 0;
int t = 0;
for(int i=0; i<boardsz; i++){
start[i] = input.nextInt();
start[i]--;
for(int s=0; s<i; s++)
if(start[s] > start[i]) del++;
if(start[i] < 0) t=i;
}
if(((row(t)+col(t)+del+rowsz) & 0x1) == 0)
System.out.println("No Solution!");
else
idastar();
}
}
private static boolean solve(int l, int t, int p){
int d,q,del;
pos[l]=p; q=pos[l-1];
if(t == 0) {out(l,q); return true;}
if(t > 0)
for(d=0; d<4; d++){
int[] pp = {p};
del = trymove(pp,q,d);
p = pp[0];
if(del>0 && solve(l+1,t-del,p)) return true;
if(del > 0) p=restore(p,d);
}
return false;
}
private static int trymove(int[] pp, int q, int d){
int p = pp[0];
int del=0;
switch (d){
case 0://right
if(col(p)<=rowsz-2 && q!=p+1){
q = p+1;
del = (col(board[q])<col(q) ? 0x1 : 0x100);
}
break;
case 1://up
if(row(p)>=1 && q!=p-rowsz){
q = p-rowsz;
del = (row(board[q])>row(q) ? 0x1 : 0x100);
}
break;
case 2://left
if(col(p)>=1 && q!=p-1){
q = p-1;
del = (col(board[q])>col(q) ? 0x1 : 0x100);
}
break;
case 3://down
if(row(p)<=rowsz-2 && q!=p+rowsz){
q = p+rowsz;
del = (row(board[q])<row(q) ? 0x1 : 0x100);
}
}
if(del > 0) {board[p]=board[q]; pp[0]=q;}
return del;
}
private static int restore(int p, int d){
int q = p-1; //right
if(d == 1) q=p+rowsz;//up
if(d == 2) q=p+1; //left
if(d == 3) q=p-rowsz;//down
board[p] = board[q];
return q;
}
private static void idastar(){
int p = initState();
if(moves == 0) {out(0,0); return;}
while (!solve(1,moves,p)) moves += 0x101;
}
private static int initState(){
int j,del,p=0;
for(j=moves=0; j<boardsz; j++)
if(start[j] >= 0){
del = row(start[j])-row(j);
moves += del<0?-del:del;
del = col(start[j])-col(j);
moves += del<0?-del:del;
}
pos[0] = boardsz;
for(j=0; j<boardsz; j++){
board[j] = start[j];
if(board[j] < 0) p=j;
}
return p;
}
private static int row(int x){
return x/rowsz;
}
private static int col(int x){
return x%rowsz;
}
private static void out(int l, int q){
pos[l+1] = q;
System.out.println((moves&0xff)+(moves>>8));
if(moves > 0){
for(int j=0; j<boardsz; j++) board[j]=start[j];
for(int k=1; k<l; k++){
System.out.print((board[pos[k+1]]+1)+" ");
board[pos[k]] = board[pos[k+1]];
}
}
}
}
Input & Output
3
1 2 3
4 0 6
7 5 8
2
5 8
3
6 7 3
2 5 1
8 4 0
26
1 5 7 6 2 7 6 3 5 6 4 1 6 5 3 4 1 8 7 1 4 2 1 4 5 6
Reference
王曉東《計算機演算法設計與分析》