算法课程-8puzzle-作业

题意理解

求解8puzzle游戏, 使用A*算法。

问题分析

这个用到了优先级队列,堆排序。但是作业太难了。把A*算法融进来,把树结构融进来。树结构的存储模式是双亲表示法。优先级队列就看起来太简单了。得分97分。

其他

参考https://www.cnblogs.com/evasean/p/7281901.html

链接

/* *****************************************************************************
 *  Name:
 *  Date:
 *  Description:
 **************************************************************************** */

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.StdOut;



public class Board {
    private int[][] boardValue;
    private final int dim;

    // create a board from an n-by-n array of tiles,
    // where tiles[row][col] = tile at (row, col)
    public Board(int[][] tiles) {
        dim = tiles.length;
        boardValue = new int[dim][dim];
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                boardValue[i][j] = tiles[i][j];
            }
        }
    }

    // string representation of this board
    public String toString() {
        StringBuilder s = new StringBuilder();
        s.append(dim + "\n");
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                s.append(String.format("%2d ", boardValue[i][j]));
            }
            s.append("\n");
        }
        return s.toString();
    }

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

    // number of tiles out of place
    public int hamming() {
        int dis = 0;
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                if (boardValue[i][j] != 0 && boardValue[i][j] != i * dim + j + 1) {
                    dis ++;
                }
            }
        }
        return dis;
    }

    // sum of Manhattan distances between tiles and goal
    public int manhattan() {
        int dis = 0;
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                if (boardValue[i][j] != 0) {
                    int value = boardValue[i][j];
                    int row_target = (value - 1) / dim;
                    int col_target = (value - 1) % dim;
                    int curr_dis = Math.abs(i - row_target) + Math.abs(j - col_target);
                    dis += curr_dis;
                }
            }
        }
        return dis;
    }

    // is this board the goal board?
    public boolean isGoal() {
        if (this.hamming() == 0) {
            return true;
        }
        return false;
    }

    // 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 target = (Board) y;
        if (this.dimension() != target.dimension()) {
            return false;
        }
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                if (this.boardValue[i][j] != target.boardValue[i][j]) {
                    return false;
                }
            }
        }
        return true;
    }

    // all neighboring boards
    public Iterable neighbors() {
        int zeroRow = -1;
        int zeroCol = -1;
        int[][] clones = new int[dim][dim];
        //find zero postion
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                if (boardValue[i][j] == 0) {
                    zeroRow = i;
                    zeroCol = j;
                }
                clones[i][j]= boardValue[i][j];
            }
        }
        //StdOut.println("zeroRow=" + zeroRow + ";zeroCol=" + zeroCol);
        Stack neighbors = new Stack();
        if (zeroRow - 1 >= 0) { //left
            clones[zeroRow][zeroCol] = clones[zeroRow - 1][zeroCol];
            clones[zeroRow - 1][zeroCol] = 0;
            neighbors.push(new Board(clones));
            clones[zeroRow - 1][zeroCol] = clones[zeroRow][zeroCol];
            clones[zeroRow][zeroCol] = 0;
        }
        if (zeroRow + 1 <= dim - 1) {
            clones[zeroRow][zeroCol] = clones[zeroRow + 1][zeroCol];
            clones[zeroRow + 1][zeroCol] = 0;
            neighbors.push(new Board(clones));
            clones[zeroRow + 1][zeroCol] = clones[zeroRow][zeroCol];
            clones[zeroRow][zeroCol] = 0;
        }
        if (zeroCol - 1 >= 0) {
            clones[zeroRow][zeroCol] = clones[zeroRow][zeroCol - 1];
            clones[zeroRow][zeroCol - 1] = 0;
            neighbors.push(new Board(clones));
            clones[zeroRow][zeroCol - 1] = clones[zeroRow][zeroCol];
            clones[zeroRow][zeroCol] = 0;
        }
        if (zeroCol + 1 <= dim - 1) {
            clones[zeroRow][zeroCol] = clones[zeroRow][zeroCol + 1];
            clones[zeroRow][zeroCol + 1] = 0;
            neighbors.push(new Board(clones));
            clones[zeroRow][zeroCol + 1] = clones[zeroRow][zeroCol];
            clones[zeroRow][zeroCol] = 0;
        }
        return neighbors;
    }

    // a board that is obtained by exchanging any pair of tiles
    public Board twin() {
        Board twinBoard = this;
        int row = 0;
        int col = 0;
        if (twinBoard.boardValue[0][0]  == 0) {
            col = 1;
        }
        for (int i = 0; i < dim; i++) {
            for (int j = 0; j < dim; j++) {
                if (twinBoard.boardValue[i][j] != twinBoard.boardValue[row][col] &&
                        twinBoard.boardValue[i][j] != 0) {
                    int tmp = twinBoard.boardValue[i][j];
                    twinBoard.boardValue[i][j] = twinBoard.boardValue[row][col];
                    twinBoard.boardValue[row][col] = tmp;
                    return twinBoard;
                }
            }
        }
        return this;
    }

    public static void main(String[] args) {
        In in = new In(args[0]);
        int n = in.readInt();
        int[][] tiles = new int[n][n];
        for(int i = 0; i < n; i ++) {
            for(int j = 0; j < n; j++) {
                tiles[i][j] = in.readInt();
            }
        }
        Board board = new Board(tiles);

        StdOut.println(board.toString());
        StdOut.println(board.dimension());
        StdOut.println(board.hamming());
        StdOut.println(board.manhattan());
        for (Board neighbor : board.neighbors()) {
            StdOut.println(neighbor);
        }
        StdOut.println(board.isGoal());
    }
}
/* *****************************************************************************
 *  Name:
 *  Date:
 *  Description:
 **************************************************************************** */

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

public class Solver {

    private SearchNode currentNode; //input
    private SearchNode twinCurrentNode;  //tuning
    private Stack solution;  //output

    // find a solution to the initial board (using the A* algorithm)
    public Solver(Board initial) {
        if (initial == null) {
            throw new IllegalArgumentException();
        }
        currentNode = new SearchNode(initial,null);
        twinCurrentNode = new SearchNode(initial.twin(), null);
        MinPQ priorityQueue = new MinPQ();
        MinPQ twinPriorityQueue = new MinPQ();
        priorityQueue.insert(currentNode);
        twinPriorityQueue.insert(twinCurrentNode);
        while (true) {
            currentNode = priorityQueue.delMin();
            if(currentNode.currentBoard.isGoal()) {
                break;
            }
            Iterable neighbors = currentNode.currentBoard.neighbors();
            for(Board neighbor : neighbors) {
                if (currentNode.preSearchNode == null ||
                !neighbor.equals(currentNode.preSearchNode.currentBoard)) {
                        priorityQueue.insert(new SearchNode(neighbor, currentNode));
                }
            }
            twinCurrentNode = twinPriorityQueue.delMin();
            if(twinCurrentNode.currentBoard.isGoal()) {
                break;
            }
            Iterable twinNeighbors = twinCurrentNode.currentBoard.neighbors();
            for(Board twinNeighbor : twinNeighbors) {
                if (twinCurrentNode.preSearchNode == null ||
                !twinNeighbor.equals(twinCurrentNode.preSearchNode.currentBoard)) {
                    twinPriorityQueue.insert(new SearchNode(twinNeighbor, twinCurrentNode));
                }
            }
        }
    }
    private class SearchNode implements Comparable {
        public Board currentBoard;
        public SearchNode preSearchNode;
        public int moves;
        public int priority;
        public SearchNode(Board myCurrentBoard, SearchNode myPreSearchNode) {
            currentBoard = myCurrentBoard;
            preSearchNode = myPreSearchNode;
            if (myPreSearchNode == null) {
                moves = 0;
            }
            else {
                moves = myPreSearchNode.moves + 1;
            }
            priority = moves + currentBoard.manhattan();
        }

        @Override
        public int compareTo(SearchNode o) {
            return Integer.compare(this.priority, o.priority);
        }
    }
    // is the initial board solvable? (see below)
    public boolean isSolvable() {
        return currentNode.currentBoard.isGoal();
    }

    // min number of moves to solve initial board
    public int moves() {
        if (currentNode.currentBoard.isGoal()) {
            return currentNode.moves;
        }
        else {
            return -1;
        }
    }

    // sequence of boards in a shortest solution
    public Iterable solution() {
        if (currentNode.currentBoard.isGoal()) {
            solution = new Stack();
            SearchNode node = currentNode;
            while (node != null) {
                solution.push(node.currentBoard);
                node = node.preSearchNode;
            }
            return solution;
        }
        else {
            return null;
        }
    }

    // test client (see below)
    public static void main(String[] args) {
        // create initial board from file
        In in = new In(args[0]);
        int n = in.readInt();
        int[][] tiles = new int[n][n];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                tiles[i][j] = in.readInt();
        Board initial = new Board(tiles);

        // solve the puzzle
        Solver solver = new Solver(initial);

        // print solution to standard output
        if (!solver.isSolvable())
            StdOut.println("No solution possible");
        else {
            StdOut.println("Minimum number of moves = " + solver.moves());
            for (Board board : solver.solution())
                StdOut.println(board);
        }
    }
}

 

你可能感兴趣的:(算法)