您的位置:首页 > 其它

普林斯顿算法课第四周作业

2015-02-16 10:14 323 查看

8 Puzzle

作业地址:http://coursera.cs.princeton.edu/algs4/assignments/8puzzle.html

----------------------------------------------------------------------------------------------------------
第四周作业 8 Puzzle

8 puzzle 是一个经典的拼图问题

将九宫格内乱序的8个数字按顺序整理好,一次只能移动一个数字到空位当中。

作业中提供的思路是Best-first search(最好优先搜索)

首先定义一个Search Node,记录初始到达当前状态的移动次数和上一个状态。

通过不断从优先级队列中取出Search Node 去寻找下一级的状态,并在其中找到最符合优先级的结果。

而要确定优先级就要使用以下两个方法:

Hamming priority function:表示不在目标位置的数目

Manhattan priority function:所有方块距离目标位置之和。



然后是需要注意的几个问题:

1.A critical optimization

防止重复状态的出现,需要进行判断

2.Game Tree 将状态以搜索树的方式储存,每一个节点对应一个状态。在每一步中,用A*算法

删除优先级队列中权值最小的那个节点。



3.Detecting infeasible puzzles

有一些初始状态是不可能得到目的状态的。题目中给我们的方法是,将同行的两个数进行交换,

如果其中一个得到目标解,那么另外一个则不可能。

最后有一些方法可能使用不当,很多都超时了

代码如下:

Board.java
import java.util.Arrays;
import java.util.Comparator;

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

// construct a board from an N-by-N array of blocks
// (where blocks[i][j] = block in row i, column j)
public Board(int[][] blocks){
N = blocks.length;
this.blocks = new int
[];
for (int i=0; i<N; i++){
this.blocks[i] = Arrays.copyOf(blocks[i], N);
}

}

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

// number of blocks out of place
public int hamming(){
int i_hamming = 0;
for (int i=0; i<N; i++){
for (int j=0; j<N && i+j < 2*N - 2; j++){
if (blocks[i][j] != i*N + j + 1){
i_hamming++;
}
}
}
return i_hamming;
}

// sum of Manhattan distances between blocks and goal
public int manhattan(){
int i_manhattan = 0;
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
if (blocks[i][j] != 0){
i_manhattan += Math.abs((blocks[i][j] - 1) % N - j) + Math.abs((blocks[i][j] - 1) / N - i);
}
}
}
return i_manhattan;
}

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

// a board obtained by exchanging two adjacent blocks in the same row
public Board twin(){
int[][] twinBoard = new int

;
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
twinBoard[i][j] = blocks[i][j];
}
}
if (blocks[0][0] != 0 && blocks[0][1] != 0){
int temp = twinBoard[0][0];
twinBoard[0][0] = twinBoard[0][1];
twinBoard[0][1] = temp;
}else{
int temp = twinBoard[1][0];
twinBoard[1][0] = twinBoard[1][1];
twinBoard[1][1] = temp;
}
return new Board(twinBoard);
}

// 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 thatBoard = (Board)y;
if (this.N != thatBoard.N){
return false;
}

int[][] arr_thatBoard = thatBoard.blocks;
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
if (blocks[i][j] != arr_thatBoard[i][j]){
return false;
}
}
}
return true;
}

// all neighboring boards
public Iterable<Board> neighbors(){
int blank_i = N;
int blank_j = N;
for (int i=0; i<N; i++){
for (int j=0; j<N; j++){
if (blocks[i][j] == 0){
//this is where the blank is
blank_i = i;
blank_j = j;
}
}
}
MinPQ<Board> q = new MinPQ<Board>(new Comparator<Board>() {
public int compare(Board o1, Board o2) {
if (o1.manhattan() < o2.manhattan()) return -1;
else if (o1.manhattan() == o2.manhattan()) return 0;
else return 1;
}
});
if (blank_j - 1 >= 0){
int[][] arr_temp = getCopy();
arr_temp[blank_i][blank_j] = arr_temp[blank_i][blank_j - 1];
arr_temp[blank_i][blank_j - 1] = 0;
q.insert(new Board(arr_temp));
//    		arr_temp = blocks.clone();
}
if (blank_j + 1 < N){
int[][] arr_temp = getCopy();
arr_temp[blank_i][blank_j] = arr_temp[blank_i][blank_j + 1];
arr_temp[blank_i][blank_j + 1] = 0;
q.insert(new Board(arr_temp));
//    		arr_temp = blocks.clone();
}
if (blank_i - 1 >= 0){
int[][] arr_temp = getCopy();
arr_temp[blank_i][blank_j] = arr_temp[blank_i - 1][blank_j];
arr_temp[blank_i - 1][blank_j] = 0;
q.insert(new Board(arr_temp));
//    		arr_temp = blocks.clone();
}
if (blank_i + 1 < N){
int[][] arr_temp = getCopy();
arr_temp[blank_i][blank_j] = arr_temp[blank_i + 1][blank_j];
arr_temp[blank_i + 1][blank_j] = 0;
q.insert(new Board(arr_temp));
//    		arr_temp = blocks.clone();
}
return q;
}

// string representation of the board (in the output format specified below)
public String toString() {
StringBuilder s = new StringBuilder();
s.append(N + "\n");
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
s.append(String.format("%2d ", blocks[i][j]));
}
s.append("\n");
}
return s.toString();
}

private int[][] getCopy(){
int[][] result = new int
[];
for (int i=0; i<N; i++){
result[i] = Arrays.copyOf(blocks[i], N);
}
return result;
}

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

;
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
blocks[i][j] = in.readInt();
Board initial = new Board(blocks);
StdOut.println(initial);
StdOut.println(initial.hamming());
}
}


Solver.java
import java.util.Comparator;

public class Solver {
private boolean isSolve = false;
private int move = -1;

private class SearchNode implements Comparable<SearchNode>{
private final Board board;
private final int move;
private final int priority;
private final SearchNode parent;
private final boolean isTwin;

public SearchNode(Board board, int move, SearchNode parent, boolean isTwin){
this.board = board;
this.move = move;
this.priority = board.manhattan() + move;
this.parent = parent;
this.isTwin = isTwin;
}

@Override
public int compareTo(SearchNode that) {
if (this.board.equals(that.board)) return 0;
if (this.priority < that.priority) return -1;
else return 1;
}
}

private MinPQ<SearchNode> minPQ = new MinPQ<SearchNode>(new Comparator<SearchNode>() {
public int compare(SearchNode o1, SearchNode o2) {
if (o1.priority < o2.priority) return -1;
else if (o1.priority == o2.priority) return 0;
else return 1;
}
});

private Stack<Board> solutionQueue = new Stack<Board>();

// find a solution to the initial board (using the A* algorithm)
public Solver(Board initial){
Board initialTwin = initial.twin();
SearchNode initSearchNode = new SearchNode(initial, 0, null, false);
SearchNode initSearchNodeTwin = new SearchNode(initialTwin, 0, null, true);
minPQ.insert(initSearchNode);
minPQ.insert(initSearchNodeTwin);
solve();
}

private void solve(){
while(true){
//solve for original
SearchNode searchNode = minPQ.delMin();
if (searchNode.board.isGoal()){
if (searchNode.isTwin){
this.isSolve = false;
this.move = -1;
} else {
this.isSolve = true;
this.move = searchNode.move;
this.solutionQueue.push(searchNode.board);
while(searchNode.parent != null){
searchNode = searchNode.parent;
this.solutionQueue.push(searchNode.board);
}
}
break;
}else{
for (Board neiborBoard: searchNode.board.neighbors()){
SearchNode neiborNode = new SearchNode(neiborBoard, searchNode.move+1, searchNode, searchNode.isTwin);
if (searchNode.parent == null){
minPQ.insert(neiborNode);
} else if (!searchNode.parent.board.equals(neiborNode.board)){
minPQ.insert(neiborNode);
}
}
}
}
}

// is the initial board solvable?
public boolean isSolvable(){
return this.isSolve;
}

// min number of moves to solve initial board; -1 if no solution
public int moves(){
return this.move;
}

// sequence of boards in a shortest solution; null if no solution
public Iterable<Board> solution(){
if (this.isSolve){
return this.solutionQueue;
}else{
return null;
}

}

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

;
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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: