8 Puzzle

8 Puzzle

Board.java

照着API写即可。注意每次调用twin()都要返回相同的值,即twin()只能交换两个固定位置的数字。

import edu.princeton.cs.algs4.StdRandom;

import java.util.ArrayList;
import java.util.List;

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

    // create a board from an n-by-n array of tiles,
    // where tiles[row][col] = tile at (row, col)
    public Board(int[][] tiles) {
        size = tiles[0].length;
        // 注意需要拷贝而不是直接引用,不然所有的Board对象使用的都是同一个二维数组
        this.tiles = new int[size][size];
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                this.tiles[i][j] = tiles[i][j];
            }
        }
    }

    // string representation of this board
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(size + "\n");
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (j == 0) {
                    sb.append(tiles[i][j]);
                } else {
                    sb.append(" " + tiles[i][j]);
                }
            }
            sb.append("\n");
        }
        return sb.toString();
    }

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

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

    // sum of Manhattan distances between tiles and goal
    public int manhattan() {
        int sum = 0;
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (tiles[i][j] != 0 && tiles[i][j] != i * size + j + 1) {
                    int ii = (tiles[i][j] - 1) / size;
                    int jj = (tiles[i][j] - 1) % size;
                    sum += Math.abs(ii - i) + Math.abs(jj - j);
                }
            }
        }
        return sum;
    }

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

    // does this board equal y?
    public boolean equals(Object y) {
        if (y == null) {
            return false;
        }
        if (y == this) {
            return true;
        }
        if (this.getClass().isInstance(y)) {
            Board that = (Board) y;
            if (this.size != that.size) {
                return false;
            }
            for (int i = 0; i < this.size; i++) {
                for (int j = 0; j < this.size; j++) {
                    if (this.tiles[i][j] != that.tiles[i][j]) {
                        return false;
                    }
                }
            }
            return true;
        } else {
            return false;
        }
    }

    // all neighboring boards
    public Iterable<Board> neighbors() {
        List<Board> neighbors = new ArrayList<>();
        int blankI = 0, blankJ = 0;
        OUTER:
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (tiles[i][j] == 0) {
                    blankI = i;
                    blankJ = j;
                    break OUTER;
                }
            }
        }
        if (blankI > 0) {
            Board up = new Board(tiles);
            up.swap(blankI, blankJ, blankI - 1, blankJ);
            neighbors.add(up);
        }
        if (blankI < size - 1) {
            Board down = new Board(tiles);
            down.swap(blankI, blankJ, blankI + 1, blankJ);
            neighbors.add(down);
        }
        if (blankJ > 0) {
            Board left = new Board(tiles);
            left.swap(blankI, blankJ, blankI, blankJ - 1);
            neighbors.add(left);
        }
        if (blankJ < size - 1) {
            Board right = new Board(tiles);
            right.swap(blankI, blankJ, blankI, blankJ + 1);
            neighbors.add(right);
        }
        return neighbors;
    }

    // a board that is obtained by exchanging any pair of tiles
    public Board twin() {
        Board twin = new Board(tiles);
        int i = 0, j = 1, m = 1, n = 0;
        while (tiles[i][j] == 0) {
            i++;
        }
        while (tiles[m][n] == 0) {
            n++;
        }
        twin.swap(i, j, m, n);
        return twin;
    }

    private void swap(int i, int j, int m, int n) {
        int temp = tiles[i][j];
        tiles[i][j] = tiles[m][n];
        tiles[m][n] = temp;
    }

    // unit testing (not graded)
    public static void main(String[] args) {
        int[][] test = {{0, 1, 3}, {4, 2, 5}, {7, 8, 6}};
        Board board = new Board(test);
        System.out.println(board);
        for (Board b : board.neighbors()) {
            System.out.println(b);
        }
        System.out.println(board.twin());
        System.out.println(board.manhattan());
    }
}

Solver.java

对于是否有解法的判断:同时处理两个数组,一个是原数组,另一个是原数组调用twin()后的数组,两数组中只要确定一个有解法,那另一个就没有解法。

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Solver {
    private Node cur;

    // find a solution to the initial board (using the A* algorithm)
    public Solver(Board initial) {
        if (initial == null) {
            throw new IllegalArgumentException();
        }
        MinPQ<Node> pq = new MinPQ<>();
        MinPQ<Node> pqTwin = new MinPQ<>();
        pq.insert(new Node(initial, null));
        pqTwin.insert(new Node(initial.twin(), null));
        while (true) {
            cur = pq.delMin();
            if (cur.isGoal()) {
                break;
            }
            insertNeighbors(pq, cur);

            Node curTwin = pqTwin.delMin();
            if (curTwin.isGoal()) {
                break;
            }
            insertNeighbors(pqTwin, curTwin);
        }
    }

    // is the initial board solvable? (see below)
    public boolean isSolvable() {
        return cur.isGoal();
    }

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

    // sequence of boards in a shortest solution
    public Iterable<Board> solution() {
        if (isSolvable()) {
            List<Board> path = new ArrayList<>();
            Node temp = cur;
            while (temp != null) {
                path.add(temp.board);
                temp = temp.prev;
            }
            Collections.reverse(path);
            return path;
        } else {
            return null;
        }

    }

    private void insertNeighbors(MinPQ<Node> pq, Node node) {
        for (Board neighbor : node.getNeighbors()) {
            if (node.prev == null || !neighbor.equals(node.prev.board)) {
                pq.insert(new Node(neighbor, node));
            }
        }
    }


    private class Node implements Comparable<Node> {
        private final Node prev;
        private final Board board;
        private final int moves;
        private final int manhattan;
        private final int priority;

        public Node(Board board, Node prev) {
            this.board = board;
            this.prev = prev;
            manhattan = board.manhattan();
            moves = prev == null ? 0 : prev.moves + 1;
            priority = manhattan + moves;
        }

        public Iterable<Board> getNeighbors() {
            return board.neighbors();
        }

        public boolean isGoal() {
            return board.isGoal();
        }

        @Override
        public String toString() {
            return board.toString();
        }

        @Override
        public int compareTo(Node that) {
            return this.priority - that.priority;
        }
    }

    // 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);
        }
    }
}

参考

cnblogs - evasean

A*算法详解

你可能感兴趣的:(Cousera)