8-puzzle 普林斯顿 算法第四版

8-puzzle 普林斯顿 算法第四版



前言

这个assignment来自Princeton University的Coursera Algorithms, Part I
需要了解优先队列的实现。
友情链接:
8 puzzle assignment specification

一、分析

采用优先队列思想,具体实现可以使用提供的API
Board部分按照链接中的要求就可以比较容易的实现。
Solver部分参考了一些博文的做法。

二、代码

1.board

import java.util.ArrayList;
import java.util.Arrays;

public class Board {
    private final int[][] tiles;
    private final int N;

    // create a board from an n-by-n array of tiles,
    // where tiles[row][col] = tile at (row, col)
    public Board(int[][] tiles) {
        //创建(复制)一个
        this.N = tiles.length;
        this.tiles = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                this.tiles[i][j] = tiles[i][j];
            }
        }

    }

    // string representation of this board
    public String toString() {
        //StringBuilder 用于修改字符串
        StringBuilder s = new StringBuilder();
        s.append(N).append("\n");
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                s.append(" " + tiles[i][j]);
            }
            s.append("\n");
        }
        String string = s.toString();
        return string;
    }

    // board dimension n
    public int dimension() {
        return N;
    }

    // number of tiles out of place
    public int hamming() {
        int k = 0;
        int dis_hamming = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                k++;
                if (tiles[i][j] == 0) {
                } else if (k != tiles[i][j]) {
                    dis_hamming++;
                }

            }
        }
        return dis_hamming;
    }

    // sum of Manhattan distances between tiles and goal
    public int manhattan() {
        int dis_manhattan = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                int tmp = tiles[i][j];
                if (tmp == 0) {
                } else {
                    int x = (tmp - 1) / N;
                    int y = (tmp - 1) % N;
                    dis_manhattan += Math.abs(x - i) + Math.abs(y - j);
                }
            }
        }
        return dis_manhattan;
    }

    // is this board the goal board?
    public boolean isGoal() {
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                if (tiles[i][j] != 0 && tiles[i][j] != i * N + j + 1)  // blocks[i][j]位置上的元素放错
                    return false;
        return true;
    }

    // does this board equal y?
    public boolean equals(Object y) {
        if (y == this) return true;
        if (y == null) return false;
        if (y.getClass() != this.getClass())
            return false;
        Board that = (Board) y;
        if (!Arrays.equals(this.tiles, that.tiles)) return false;
        return true;
    }

    private int[][] copy() // 拷贝棋盘元素
    {
        int[][] newblocks = new int[N][N];
        for (int i1 = 0; i1 < N; i1++)
            for (int j1 = 0; j1 < N; j1++)
                newblocks[i1][j1] = this.tiles[i1][j1];
        return newblocks;
    }

    private Board swap(int i1, int j1, int i2, int j2) {
        int[][] newblocks = copy();
        int temp = newblocks[i1][j1];
        newblocks[i1][j1] = newblocks[i2][j2];
        newblocks[i2][j2] = temp;
        return new Board(newblocks);
    }

    // all neighboring boards
    public Iterable<Board> neighbors() {
        ArrayList<Board> boards;
        boards = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (tiles[i][j] == 0) {
                    if (i > 0) {
                        //head
                        Board upBoard = swap(i, j, i - 1, j);
                        boards.add(upBoard);
                    }
                    if (i < N - 1) {
                        //bottom
                        Board lowBoard = swap(i, j, i + 1, j);
                        boards.add(lowBoard);
                    }
                    if (j > 0) {
                        //left
                        Board leftBoard = swap(i, j, i, j - 1);
                        boards.add(leftBoard);
                    }

                    if (j < N - 1) {
                        //right
                        Board rightBoard = swap(i, j, i, j + 1);
                        boards.add(rightBoard);
                    }
                }
            }
        }
        return boards;
    }

    // a board that is obtained by exchanging any pair of tiles
    public Board twin() {
        int i1 = 0, j1 = 0, i2 = 1, j2 = 1;
        if (tiles[i1][j1] == 0) {
            i1 = 1;
            j1 = 0;
        }
        if (tiles[i2][j2] == 0) {
            i2 = 1;
            j2 = 0;
        }

        Board newBoard = swap(i1, j1, i2, j2);

        return newBoard;
    }

    // unit testing (not graded)
    public static void main(String[] args) {
        int[][] blocks = new int[3][3];

        blocks[0][0] = 1;
        blocks[0][1] = 2;
        blocks[0][2] = 3;

        blocks[1][0] = 4;
        blocks[1][1] = 5;
        blocks[1][2] = 6;

        blocks[2][0] = 8;
        blocks[2][1] = 7;
        blocks[2][2] = 0;
        Board board = new Board(blocks);

        System.out.println(board.manhattan());
        System.out.println(board.toString());
        for (Board it : board.neighbors()) {
            //System.out.println(it.toString());
        }

        System.out.println(board.twin().toString());

    }

}

2.solver

代码如下(示例):

import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.Stack;

public class Solver {
    private TreeNode currentNode;
    private TreeNode currenttwinNode;
    private Stack<Board> stackBoard;

    // find a solution to the initial board (using the A* algorithm)
    private class TreeNode implements Comparable<TreeNode> {
        private final Board board;
        private final TreeNode pre;
        private final int moves;
        private final int priority;

        private TreeNode(Board b, TreeNode pre) {
            this.board = b;
            this.pre = pre;
            if (pre != null) {
                this.moves = pre.moves + 1;
                this.priority = this.moves + this.board.manhattan();
            } else {
                //pre==null
                moves = 0;
                this.priority = this.moves + this.board.manhattan();
            }
        }

        public TreeNode getPre() {
            return pre;
        }

        public int getMoves() {
            return moves;
        }

        public Board getBoard() {
            return board;
        }

        public int getPriority() {
            return priority;
        }

        public int compareTo(TreeNode a) {
            if (this.priority == a.priority) {
                return this.board.manhattan() - a.board.manhattan();
            }
            return this.priority - a.priority;
        }
    }

    private final boolean solvable;

    public boolean isSolvable() {
        return solvable;
    }

    public int moves() {
        if (isSolvable())
            return currentNode.getMoves();
        else
            return -1;
    }

    public Solver(Board initial) {
        if (initial == null)
            throw new NullPointerException();

        currentNode = new TreeNode(initial, null);
        MinPQ<TreeNode> PQ = new MinPQ<>();
        PQ.insert(currentNode);

        currenttwinNode = new TreeNode(initial.twin(), null);
        MinPQ<TreeNode> twinPQ = new MinPQ<>();
        twinPQ.insert(currenttwinNode);
        //boolean flag = false;
        while (true) {
            //origin
            currentNode = PQ.delMin();
            if (currentNode.getBoard().isGoal()) {
                solvable = true;
                break;
                //found
            } else {
                for (Board it : currentNode.getBoard().neighbors()) {
                    //==null 针对第一个Node
                    if (currentNode.getPre() == null ||
                            !it.equals(currentNode.getPre().getBoard())) {
                        PQ.insert(new TreeNode(it, currentNode));
                    }
                }
            }

            //twin tiles
            currenttwinNode = twinPQ.delMin();
            if (currenttwinNode.getBoard().isGoal()) {
                solvable = false;
                break;
                //found
            } else {
                for (Board it : currenttwinNode.getBoard().neighbors()) {
                    //==null 针对第一个Node
                    if (currenttwinNode.getPre() == null ||
                            !it.equals(currenttwinNode.getPre().getBoard())) {
                        twinPQ.insert(new TreeNode(it, currenttwinNode));
                    }
                }
            }
        }

    }

    // sequence of boards in a shortest solution; null if unsolvable
    public Iterable<Board> solution() {
        if (!isSolvable())
            return null;
        stackBoard = new Stack<>();
        TreeNode nowNode = currentNode;
        while (nowNode != null) {
            stackBoard.push(nowNode.getBoard());
            nowNode = nowNode.getPre();
        }
        return stackBoard;
    }

    public static void main(String[] args) // solve a slider puzzle (given below)
    {
        int[][] blocks = new int[3][3];

        blocks[0][0] = 1;
        blocks[0][1] = 2;
        blocks[0][2] = 3;

        blocks[1][0] = 4;
        blocks[1][1] = 5;
        blocks[1][2] = 6;

        blocks[2][0] = 8;
        blocks[2][1] = 7;
        blocks[2][2] = 0;
        Board board = new Board(blocks);

        Solver solver = new Solver(board);
        //System.out.println(solver.currentNode.getPre() == null);
        //System.out.println(solver.currentNode.getPre());
        if (!solver.isSolvable()) {
            System.out.println("this board is can't resolve");
        } else {
            Iterable<Board> bIterable = solver.solution();
            //System.out.println(bIterable.toString());
            //System.out.println("444");
            System.out.println("Minimum number of moves = " + solver.moves());
            for (Board it : bIterable) {

                System.out.println(it.toString());
            }
        }


    }
}

总结

花了很多时间来搞懂到底要做什么。有一些疑问可以在链接中的答疑中知道。比如: 1.board的中的twin()是干嘛的,应为在写solver的时候要么tiles本身有解,要么它的twin()有解,因此需要两个队列来判断本事是不是有解

本代码得了89/100分,还有许多可以优化的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值