算法设计与分析: 5-37 n²-1谜问题

5-37 n²-1谜问题


问题描述

重排九宫是一个古老的单人智力游戏。据说重排九宫起源于我国古时由三国演义故事“关羽义释曹操”而设计的智力玩具“华容道”,后来流传到欧洲,将人物变成数字。原始 的重排九宫问题是这样的:将数字 1~8 按照任意次序排在 3 × 3 的方格阵列中,留下一个空 格。与空格相邻的数字,允许从上,下,左,右方向移动到空格中。游戏的最终目标是通过 合法移动,将数字 1~8 按行排好序。在一般情况下, n 2 1 谜问题是将数字 1 ~ n 2 1 按照任意次序排在 n × n 的方格阵列中,留下一个空格。允许与空格相邻的数字从上,下,左,右 4 个方向移动到空格中。游戏的最终目标是通过合法移动,将初始状态变换到目标状态。 n 2 1 谜问题的目标状态是将数字 1~ n 2 1 按从小到大的次序排列,最后一个位置为空格。

n²-1谜

对于给定的 n × n 方格阵列中数字 1~ n 2 1 初始排列,编程计算将初始排列通过合法移动 变换为目标状态最少移动次数。

数据输入:
第 1 行有 1 个正整数 n。以下的 n 行是 n × n 方格 阵列的中数字 1~ n 2 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

王晓东《计算机算法设计与分析》

猜你喜欢

转载自blog.csdn.net/ioio_/article/details/81157896