1. 程式人生 > >演算法設計與分析: 5-37 n²-1謎問題

演算法設計與分析: 5-37 n²-1謎問題

5-37 n²-1謎問題

問題描述

重排九宮是一個古老的單人智力遊戲。據說重排九宮起源於我國古時由三國演義故事“關羽義釋曹操”而設計的智力玩具“華容道”,後來流傳到歐洲,將人物變成數字。原始 的重排九宮問題是這樣的:將數字 1~8 按照任意次序排在 3×3 的方格陣列中,留下一個空 格。與空格相鄰的數字,允許從上,下,左,右方向移動到空格中。遊戲的最終目標是通過 合法移動,將數字 1~8 按行排好序。在一般情況下,n21謎問題是將數字 1 ~ n21 按照任意次序排在n×n 的方格陣列中,留下一個空格。允許與空格相鄰的數字從上,下,左,右 4 個方向移動到空格中。遊戲的最終目標是通過合法移動,將初始狀態變換到目標狀態。

n21謎問題的目標狀態是將數字 1~n21按從小到大的次序排列,最後一個位置為空格。

n²-1謎

對於給定的 n×n 方格陣列中數字 1~n21 初始排列,程式設計計算將初始排列通過合法移動 變換為目標狀態最少移動次數。

資料輸入:
第 1 行有 1 個正整數 n。以下的 n 行是 n×n 方格 陣列的中數字 1~n21 的初始排列,每行有 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

王曉東《計算機演算法設計與分析》