补第四周作业总结——8 puzzle

8 puzzle已经提供了解决思路,早期的人工智能算法A。我只能感觉它的神奇,但是没法创造性地使用它。只能按部就班地完成这周的作业。
难点在于对过程的不理解。这个3
3的格子搜索算法没有尽头,随着步数的越来越多,所耗资源也越来越大。因此,判断是否可解只能交换两个格子作为twin,同时计算两个,肯定只有一个可解。
因此用数组来表示board,很多步骤实现非常难看。
Board.java

import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.StdRandom;

public class Board {

    private int[][] blocks;
    private int blank_x; // index of blank block
    private int blank_y; // index of blank block

    public Board(int[][] blocks){
        if(blocks == null)
            throw new IllegalArgumentException();
        this.blocks = new int[blocks.length][blocks.length];
        for(int i=0; i<blocks.length; i++) {
            for(int j=0; j<blocks.length; j++) {
                this.blocks[i][j] = blocks[i][j];
                if(blocks[i][j] == 0) {
                    blank_x = i;
                    blank_y = j;
                }
            }
        }
    }

    public int dimension() {
        return blocks.length;
    }

    public int hamming() {
        int count = 0;
        for(int i=0; i<dimension(); i++) {
            for(int j=0; j<dimension(); j++) {
                if(blocks[i][j] == 0)
                    continue;
                if(blocks[i][j] != i*dimension()+j+1) {
                    count++;
                }
            }
        }
        return count;
    }

    public int manhattan() {
        int distance = 0;
        int ti=0, tj=0;
        for(int i=0; i<dimension(); i++) {
            for(int j=0; j<dimension(); j++) {
                if(blocks[i][j] == 0)
                    continue;
                ti = (blocks[i][i]-1) / dimension();
                tj = (blocks[i][j]-1) % dimension();
                distance += Math.abs(ti-i) + Math.abs(tj-j);
            }
        }
        return distance;
    }

    public boolean isGoal() {
        return hamming() == 0;
    }

    public Board twin() {
        int oi=0, oj=0;
        for(int i=0; i<dimension(); i++) {
            for(int j=0; j<dimension(); j++) {
                if(blank_y != j && blank_x != i) {
                    oi = i;
                    oj = j;
                    break;
                }
            }
        }
        int oii=0, ojj=0;
        for(int i=0; i<dimension(); i++) {
            for(int j=0; j<dimension(); j++) {
                if(blank_y != j && blank_x != i && i != oi && j != oj) {
                    oii = i;
                    ojj = j;
                    break;
                }
            }
        }
        int[][] brother = copy();
        exch(brother, oi, oj, oii, ojj);
        return new Board(brother);
    }

    @Override
    public boolean equals(Object obj) {
        if(obj == null)
            return false;
        return toString().equals(obj.toString());
    }

    public Iterable<Board> neighbors() {
        Queue<Board> que = new Queue<>();
        int[][] neighbor;
        int[][] dirs = new int[][]{
                {blank_x-1, blank_y},
                {blank_x+1, blank_y},
                {blank_x, blank_y-1},
                {blank_x, blank_y+1}
        };
        for(int[] dir : dirs){
            if(validIdx(dir)){
                neighbor = copy();
                neighbor[blank_x][blank_y] = neighbor[dir[0]][dir[1]];
                neighbor[dir[0]][dir[1]] = 0;
                que.enqueue(new Board(neighbor));
            }
        }
        return que;
    }

    private void exch(int[][] blocks, int x1, int y1, int x2, int y2) {
        int temp = blocks[x2][y2];
        blocks[x2][y2] = blocks[x1][y1];
        blocks[x1][y1] = temp;
    }

    private boolean validIdx(int[] dir) {
        if(dir[0] >= 0 && dir[0] < dimension() &&
                dir[1] >= 0 && dir[1] < dimension())
            return true;
        return false;
    }

    private int[][] copy() {
        int [][] newBlocks = new int[dimension()][dimension()];
        for(int i=0; i<dimension(); i++) {
            for(int j=0; j<dimension(); j++) {
                newBlocks[i][j] = blocks[i][j];
            }
        }
        return newBlocks;
    }

    @Override
    public String toString() {
        StringBuilder out = new StringBuilder();
        out.append(dimension()+"\n");
        for(int i=0; i<dimension(); i++) {
            for(int j=0; j<dimension(); j++) {
                out.append(" "+blocks[i][j]+" ");
            }
            out.append("\n");
        }
        return out.toString();
    }
}

Solver.java

import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.StdOut;
import java.util.Stack;

public class Solver {

    private Queue<Board> solutions;

    public Solver(Board initial) {
        if(initial == null)
            throw new IllegalArgumentException();
        find(initial);
    }

    private boolean find(Board initial) {
        MinPQ<Node> pq, qp;
        pq = new MinPQ<>();
        qp = new MinPQ<>(); // twin
        Stack<Board> process = new Stack<>();
        solutions = new Queue<>();
        pq.insert(new Node(initial, 0));
        qp.insert(new Node(initial.twin(), 0));
        while(true){
            Node chosen = pq.delMin();
            Node t_chosen = qp.delMin();
            if(chosen.board.isGoal()) {
                Node end = chosen;
                while(end != null){
                    process.add(end.board);
                    end = end.prev;
                }
                break;
            }
            if(t_chosen.board.isGoal()) {
                break;
            }
            for(Board neighbor : chosen.board.neighbors()) {
                Node n = new Node(neighbor, chosen.moves+1);
                n.prev = chosen;
                if(chosen.prev != null && neighbor.equals(chosen.prev.board)) {
                    continue; // critical optimisation
                }
                pq.insert(n);
            }
            for(Board neighbor : t_chosen.board.neighbors()) {
                Node n = new Node(neighbor, t_chosen.moves+1);
                n.prev = t_chosen;
                if(t_chosen.prev != null && neighbor.equals(t_chosen.prev.board)) {
                    continue;
                }
                qp.insert(n);
            }
        }
        while(! process.isEmpty()) {
            solutions.enqueue(process.pop());
        }
        return !solutions.isEmpty();
    }

    private class Node implements Comparable<Node>{
        public Node prev;
        public Board board;
        public int moves;
        public int priority;
        public Node(Board board, int moves) {
            this.board = board;
            this.moves = moves;
            priority = moves + board.manhattan();
        }
        @Override
        public int compareTo(Node o) {
            return priority - o.priority;
        }
    }

    public boolean isSolvable() {
        return !solutions.isEmpty();
    }

    public int moves() {
        return solutions.size()-1;
    }

    public Iterable<Board> solution() {
        if(!isSolvable())
            return null;
        return solutions;
    }

    public static void main(String[] args) {
        // create initial board from file
        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);

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

posted @ 2018-03-05 09:06  新月的力量_141  阅读(253)  评论(0编辑  收藏  举报