Coursera Algorithms第四周编程任务

Programming Assignment 4: 8 Puzzle

Write a program to solve the 8-puzzle problem (and its natural generalizations) using the A* search algorithm.

Algorithms 第四周的编程任务,主要目的是编写一个Board类来代表\(n*n\)的一个格子,一个Solver类来计算Board 类是否有解。

课程给出的四个数据类型说明(API):

Board and Solver data types. Organize your program by creating an immutable data type Board with the following API:

public class Board {
    public Board(int[][] blocks)           // construct a board from an n-by-n array of blocks
                                           // (where blocks[i][j] = block in row i, column j)
    public int dimension()                 // board dimension n
    public int hamming()                   // number of blocks out of place
    public int manhattan()                 // sum of Manhattan distances between blocks and goal
    public boolean isGoal()                // is this board the goal board?
    public Board twin()                    // a board that is obtained by exchanging any pair of blocks
    public boolean equals(Object y)        // does this board equal y?
    public Iterable<Board> neighbors()     // all neighboring boards
    public String toString()               // string representation of this board (in the output format specified below)

    public static void main(String[] args) // unit tests (not graded)
}

Also, create an immutable data type Solver with the following API:

public class Solver {
    public Solver(Board initial)           // find a solution to the initial board (using the A* algorithm)
    public boolean isSolvable()            // is the initial board solvable?
    public int moves()                     // min number of moves to solve initial board; -1 if unsolvable
    public Iterable<Board> solution()      // sequence of boards in a shortest solution; null if unsolvable
    public static void main(String[] args) // solve a slider puzzle (given below)
}

方案

Board 类,参照API以及文档书写即可,不再赘述。

实现代码

import edu.princeton.cs.algs4.Stack;

import java.util.Arrays;

/**
 * @author revc
 */
public class Board {
    private final int[] blocks1D;
    private int len;

    /**
     * construct a board from an n-by-n array of blocks (where blocks[i][j] = block in row i, column j).
     *
     * @param blocks n-by-n array of blocks.
     */
    public Board(int[][] blocks) {
        if (blocks == null) {
            throw new IllegalArgumentException();
        }
        len = blocks.length;
        this.blocks1D = new int[len * len];
        for (int i = 0; i < len; ++i) {
            System.arraycopy(blocks[i], 0, this.blocks1D, i * len, len);
        }
    }

    private Board(int[] blocks) {
        len = (int) Math.sqrt(blocks.length);
        this.blocks1D = Arrays.copyOf(blocks, blocks.length);
    }

    /**
     * Return board dimension n.
     *
     * @return board dimension n.
     */
    public int dimension() {
        return len;
    }


    /**
     * Return number of blocks out of place.
     *
     * @return number of blocks out of place.
     */
    public int hamming() {
        int ham = 0;
        for (int i = 0; i < blocks1D.length; ++i) {
            if (blocks1D[i] != 0 && blocks1D[i] != i + 1) {
                ham++;
            }
        }
        return ham;
    }

    /**
     * Return sum of Manhattan distances between blocks and goal
     *
     * @return sum of Manhattan distances between blocks and goal
     */
    public int manhattan() {
        int man = 0;
        for (int i = 0; i < blocks1D.length; ++i) {
            if (blocks1D[i] != 0 && blocks1D[i] != i + 1) {
                man += Math.abs((blocks1D[i] - 1) / len - i / len) + Math.abs((blocks1D[i] - 1) % len - i % len);
            }
        }
        return man;
    }

    /**
     * Is this board the goal board?
     *
     * @return true if this is the goal board, false otherwise.
     */
    public boolean isGoal() {
        return manhattan() == 0;
    }

    /**
     * Return a board that is obtained by exchanging any pair of blocks
     *
     * @return a board that is obtained by exchanging any pair of blocks
     */
    public Board twin() {
        int[] twinBlocks;

        if (blocks1D[0] != 0 && blocks1D[1] != 0) {
            twinBlocks = swapBlocks(0, 1);
        } else {
            twinBlocks = swapBlocks(len * len - 2, len * len - 1);
        }
        return new Board(twinBlocks);
    }


    /**
     * Does this board equal y?
     *
     * @return true if any one element in y is equal to the corresponding element of {@code this} object,
     * false otherwise.
     */
    @Override
    public boolean equals(Object y) {
        if (y == this) {
            return true;
        }
        if (y == null || y.getClass() != this.getClass()) {
            return false;
        }
        Board that = (Board) y;
        return this.dimension() == that.dimension() && Arrays.equals(this.blocks1D, that.blocks1D);
    }

    /**
     * Return all neighboring boards that exchanged the blank block and one of the blocks around the blank block.
     *
     * @return all neighboring boards.
     */
    public Iterable<Board> neighbors() {
        Stack<Board> neighbors = new Stack<>();
        int[] swappedBlocks;
        int indexOfBlank = -1;
        int indexOfNeighborBlock;

        while (blocks1D[++indexOfBlank] != 0) {
        }

        int[] diffX = {-1, 1, 0, 0};
        int[] diffY = {0, 0, -1, 1};

        for (int i = 0; i < 4; ++i) {

            int rowOfNeighbourBlock = indexOfBlank / len + diffX[i];
            int colOfNeighbourBlock = indexOfBlank % len + diffY[i];

            if (rowOfNeighbourBlock >= 0 && rowOfNeighbourBlock < len && colOfNeighbourBlock >= 0 && colOfNeighbourBlock < len) {

                indexOfNeighborBlock = rowOfNeighbourBlock * len + colOfNeighbourBlock;

                swappedBlocks = swapBlocks(indexOfBlank, indexOfNeighborBlock);
                neighbors.push(new Board(swappedBlocks));
            }
        }
        return neighbors;
    }


    /**
     * exchange the positions of the two blocks
     */
    private int[] swapBlocks(int i, int j) {
        int[] blocks = Arrays.copyOf(blocks1D, blocks1D.length);
        int swap = blocks[i];
        blocks[i] = blocks[j];
        blocks[j] = swap;
        return blocks;
    }

    /**
     * Return string representation of this board.
     *
     * @return string representation of this board.
     */
    @Override
    public String toString() {
        StringBuilder board = new StringBuilder();

        board.append(len).append("\n");
        for (int i = 0; i < blocks1D.length; i++) {
            board.append(String.format("%2d ", blocks1D[i]));
            if ((i + 1) % len == 0) {
                board.append("\n");
            }
        }
        return board.toString();
    }
}

Solver类,我们同时采用两个MinPQ一个用于处理当前Board,另一个处理Twin,取出最小优先级对象的同时,不断将neighbors对象加入到MinPQ中,直至两个MinPQ中的任意一方,到达目标位置。一个小优化:我们可以通过比较当前节点和祖父节点来避免相同节点的加入。

实现代码

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

/**
 * @author revc
 */
public class Solver {
    private boolean solvable;
    private int moves;
    private SearchNode current;

    /**
     * Find a solution to the initial board (using the A* algorithm).
     */
    public Solver(Board initial) {
        if (initial == null) {
            throw new IllegalArgumentException();
        }

        MinPQ<SearchNode> pq = new MinPQ<>();
        MinPQ<SearchNode> pqTwin = new MinPQ<>();

        SearchNode node;
        SearchNode nodeTwin;

        pq.insert(new SearchNode(initial, 0, null));
        pqTwin.insert(new SearchNode(initial.twin(), 0, null));

        while (!(pq.min().board.isGoal() || pqTwin.min().board.isGoal())) {

            node = pq.delMin();
            nodeTwin = pqTwin.delMin();

            for (Board board : node.board.neighbors()) {
                if (node.moves == 0 || !board.equals(node.previous.board)) {
                    pq.insert(new SearchNode(board, node.moves + 1, node));
                }
            }

            for (Board board : nodeTwin.board.neighbors()) {
                if (nodeTwin.moves == 0 || !board.equals(nodeTwin.previous.board)) {
                    pqTwin.insert(new SearchNode(board, nodeTwin.moves + 1, nodeTwin));
                }
            }

        }
        solvable = pq.min().board.isGoal();
        current = pq.min();
        moves = pq.min().moves;
    }

    /**
     * Is the initial board solvable?
     *
     * @return true if the initial board is solvable, false otherwise.
     */
    public boolean isSolvable() {
        return solvable;
    }

    /**
     * Min number of moves to solve initial board; -1 if unsolvable
     *
     * @return min number of moves to solve initial board.
     */
    public int moves() {
        if (!isSolvable()) {
            return -1;
        }
        return moves;
    }

    /**
     * Return sequence of boards in a shortest solution; null if unsolvable.
     *
     * @return sequence of boards in a shortest solution; null if unsolvable.
     */
    public Iterable<Board> solution() {
        if (!isSolvable()) {
            return null;
        }

        Stack<Board> boards = new Stack<>();
        SearchNode node = current;

        while (node != null) {
            boards.push(node.board);
            node = node.previous;
        }
        return boards;
    }

    private class SearchNode implements Comparable<SearchNode> {
        Board board;
        SearchNode previous;
        int moves;
        int priority;


        SearchNode(Board board, int moves, SearchNode previous) {
            this.board = board;
            this.moves = moves;
            priority = this.moves + this.board.manhattan();
            this.previous = previous;
        }

        @Override
        public int compareTo(SearchNode that) {
            if (this.priority == that.priority) {
                return this.board.manhattan() - this.board.manhattan();
            } else {
                return this.priority - that.priority;
            }
        }
    }

    /**
     * Solve a slider puzzle;
     */
    public static void main(String[] args) {
        In in = new In(args[0]);
        int n = in.readInt();
        int[][] blocks = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                blocks[i][j] = in.readInt();
            }
        }
        Board initial = new Board(blocks);

        Solver solver = new Solver(initial);

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

转载于:https://www.cnblogs.com/revc/p/9238769.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值