算法导论第四版学习——习题四8 Puzzle

题目正文:

http://coursera.cs.princeton.edu/algs4/assignments/8puzzle.html

作业难点:

1、如何验证Puzzle是否可解?题目中有提示,如果相邻两个格子交换后得到的“Twin Puzzle”进行求解,如果Twin有解那么原始Puzzle就无解。

作业技巧:

1、checklist提到把Twin Puzzle和Puzzle放在一个Priority Queue中,其实就是在设计自己的Node数据结构的时候加一个boolean类型标识是否twin就好了

2、别忘了Equal的实现要素,首先是否为空、其次是否类型一致、再其次维度是否一致、最后逐个比较。

代码参考:

(这是我自己亲测100分的答案,不代表写得最好,请在自己实在完成不了的时候再看,不然的话做这个题目的意义一点都没有)

  1 import edu.princeton.cs.algs4.In;
  2 import edu.princeton.cs.algs4.StdOut;
  3 
  4 import java.util.Stack;
  5 
  6 
  7 public class Board {
  8     private int ngrid;
  9     private char[] board;
 10     private int hammingCache;
 11     private int manhattanCache;
 12 
 13     public Board(int[][] blocks) {
 14         ngrid = blocks.length;
 15 
 16         if (ngrid < 2) {
 17             throw new NullPointerException();
 18         }
 19 
 20         board = new char[ngrid * ngrid];
 21         hammingCache = 0;
 22         manhattanCache = 0;
 23 
 24         for (int i = 0; i < ngrid; i++) {
 25             for (int j = 0; j < ngrid; j++) {
 26                 int currentValue = blocks[i][j];
 27                 board[(i * ngrid) + j] = (char) currentValue;
 28 
 29                 if (currentValue != 0) {
 30                     if (currentValue != ((i * ngrid) + j + 1)) {
 31                         hammingCache++;
 32                     }
 33 
 34                     int col = (currentValue - 1) % ngrid;
 35                     int row = (currentValue - col - 1) / ngrid;
 36                     // StdOut.println("v:"+currentValue+"r:"+row+"c:"+col);
 37                     manhattanCache += (((col > j) ? (col - j) : (j - col)) +
 38                     ((row > i) ? (row - i) : (i - row)));
 39                 }
 40             }
 41         }
 42     }
 43 
 44     public int dimension() // board dimension n
 45      {
 46         return ngrid;
 47     }
 48 
 49     public int hamming() // number of blocks out of place
 50      {
 51         return hammingCache;
 52     }
 53 
 54     public int manhattan() // sum of Manhattan distances between blocks and goal
 55      {
 56         return manhattanCache;
 57     }
 58 
 59     public boolean isGoal() // is this board the goal board?
 60      {
 61         return hammingCache == 0;
 62     }
 63 
 64     public Board twin() // a board that is obtained by exchanging any pair of blocks
 65      {
 66         int[][] twin = new int[ngrid][ngrid];
 67 
 68         for (int i = 0; i < ngrid; i++) {
 69             for (int j = 0; j < ngrid; j++) {
 70                 twin[i][j] = (int) board[(i * ngrid) + j];
 71             }
 72         }
 73 
 74         if ((twin[0][0] == 0) || (twin[0][1] == 0)) {
 75             swap(twin, 1, 0, 1, 1);
 76         } else {
 77             swap(twin, 0, 0, 0, 1);
 78         }
 79 
 80         return new Board(twin);
 81     }
 82 
 83     public boolean equals(Object y) // does this board equal y?
 84      {
 85         if (y == this) {
 86             return true;
 87         }
 88 
 89         if (y == null) {
 90             return false;
 91         }
 92 
 93         if (y.getClass() != this.getClass()) {
 94             return false;
 95         }
 96 
 97         Board that = (Board) y;
 98         if (that.dimension() != ngrid) return false;
 99         for (int i = 0; i < (ngrid * ngrid); i++) {
100             if (this.board[i] != that.board[i]) {
101                 return false;
102             }
103         }
104 
105         return true;
106     }
107 
108     public Iterable<Board> neighbors() // all neighboring boards
109      {
110         int blankRow = 0;
111         int blankCol = 0;
112         Stack<Board> neighbours = new Stack<Board>();
113 
114         int[][] clone = new int[ngrid][ngrid];
115 
116         for (int i = 0; i < ngrid; i++) {
117             for (int j = 0; j < ngrid; j++) {
118                 clone[i][j] = (int) board[(i * ngrid) + j];
119 
120                 if (clone[i][j] == 0) {
121                     blankRow = i;
122                     blankCol = j;
123                 }
124             }
125         }
126 
127         if (blankCol != 0) {
128             swap(clone, blankRow, blankCol - 1, blankRow, blankCol);
129             neighbours.push(new Board(clone));
130             swap(clone, blankRow, blankCol - 1, blankRow, blankCol);
131         }
132 
133         if (blankCol != (ngrid - 1)) {
134             swap(clone, blankRow, blankCol + 1, blankRow, blankCol);
135             neighbours.push(new Board(clone));
136             swap(clone, blankRow, blankCol + 1, blankRow, blankCol);
137         }
138 
139         if (blankRow != 0) {
140             swap(clone, blankRow - 1, blankCol, blankRow, blankCol);
141             neighbours.push(new Board(clone));
142             swap(clone, blankRow - 1, blankCol, blankRow, blankCol);
143         }
144 
145         if (blankRow != (ngrid - 1)) {
146             swap(clone, blankRow + 1, blankCol, blankRow, blankCol);
147             neighbours.push(new Board(clone));
148         }
149 
150         return neighbours;
151     }
152 
153     private void swap(int[][] array, int i, int j, int a, int b) {
154         int temp = array[i][j];
155         array[i][j] = array[a][b];
156         array[a][b] = temp;
157     }
158 
159     public String toString() // string representation of this board (in the output format specified below)
160      {
161         StringBuilder s = new StringBuilder();
162         s.append(ngrid + "
");
163         for (int i = 0; i < ngrid; i++) {
164             for (int j = 0; j < ngrid; j++) {
165                 s.append(String.format("%2d ", (int) board[(i * ngrid) + j]));
166             }
167 
168             s.append("
");
169         }
170 
171         return s.toString();
172     }
173 
174     public static void main(String[] args) // unit tests (not graded)
175      {
176         // read in the board specified in the filename
177         In in = new In(args[0]);
178         int n = in.readInt();
179         int[][] tiles = new int[n][n];
180 
181         for (int i = 0; i < n; i++) {
182             for (int j = 0; j < n; j++) {
183                 tiles[i][j] = in.readInt();
184             }
185         }
186 
187         // solve the slider puzzle
188         Board initial = new Board(tiles);
189         StdOut.printf("hamming:%d manhattan:%d 
", initial.hamming(),
190             initial.manhattan());
191         StdOut.println("dim:" + initial.dimension());
192         StdOut.println(initial.toString());
193         StdOut.println("goal:" + initial.isGoal());
194         StdOut.println("twin:
" + initial.twin().toString());
195 
196         StdOut.println("neighbours:");
197 
198         for (Board s : initial.neighbors()) {
199             StdOut.println(s.toString());
200         }
201     }
202 }
Board
  1 import edu.princeton.cs.algs4.In;
  2 import edu.princeton.cs.algs4.MinPQ;
  3 import edu.princeton.cs.algs4.StdOut;
  4 
  5 import java.util.Stack;
  6 
  7 
  8 public class Solver {
  9     private boolean solvable;
 10     private GameNode originLast;
 11 
 12     public Solver(Board initial) // find a solution to the initial board (using the A* algorithm)
 13      {
 14         if (initial == null) {
 15             throw new NullPointerException();
 16         }
 17 
 18         solvable = true;
 19 
 20         MinPQ<GameNode> queue = new MinPQ<GameNode>();
 21 
 22         queue.insert(new GameNode(initial, null, 0, false));
 23         queue.insert(new GameNode(initial.twin(), null, 0, true));
 24 
 25         while (!queue.isEmpty()) {
 26             GameNode processed = queue.delMin();
 27 
 28             if (!processed.isTwin) {
 29                 originLast = processed;
 30             }
 31 
 32             if (processed.boardValue.isGoal()) {
 33                 if (processed.isTwin) {
 34                     solvable = false;
 35                 }
 36 
 37                 break;
 38             }
 39 
 40             for (Board neighbor : processed.boardValue.neighbors()) {
 41                 if ((processed.prev == null) ||
 42                         !processed.prev.boardValue.equals(neighbor)) {
 43                     queue.insert(new GameNode(neighbor, processed,
 44                             processed.moves + 1, processed.isTwin));
 45                 }
 46             }
 47         }
 48     }
 49 
 50     public boolean isSolvable() // is the initial board solvable?
 51      {
 52         return solvable;
 53     }
 54 
 55     public int moves() // min number of moves to solve initial board; -1 if unsolvable
 56      {
 57         if (isSolvable()) {
 58             return originLast.moves;
 59         } else {
 60             return -1;
 61         }
 62     }
 63 
 64     public Iterable<Board> solution() // sequence of boards in a shortest solution; null if unsolvable
 65      {
 66         if (!isSolvable()) {
 67             return null;
 68         }
 69 
 70         Stack<Board> solutions = new Stack<Board>();
 71         GameNode current = originLast;
 72 
 73         while (current.prev != null) {
 74             solutions.push(current.boardValue);
 75             current = current.prev;
 76         }
 77 
 78         solutions.push(current.boardValue);
 79 
 80         Stack<Board> solutions2 = new Stack<Board>();
 81 
 82         while (!solutions.empty()) {
 83             solutions2.push(solutions.pop());
 84         }
 85 
 86         return solutions2;
 87     }
 88 
 89     public static void main(String[] args) {
 90         // create initial board from file
 91         In in = new In(args[0]);
 92         int n = in.readInt();
 93         int[][] blocks = new int[n][n];
 94 
 95         for (int i = 0; i < n; i++)
 96             for (int j = 0; j < n; j++)
 97                 blocks[i][j] = in.readInt();
 98 
 99         Board initial = new Board(blocks);
100 
101         // solve the puzzle
102         Solver solver = new Solver(initial);
103 
104         // print solution to standard output
105         if (!solver.isSolvable()) {
106             StdOut.println("No solution possible");
107         } else {
108             StdOut.println("Minimum number of moves = " + solver.moves());
109 
110             for (Board board : solver.solution())
111                 StdOut.println(board);
112         }
113     }
114 
115     private class GameNode implements Comparable<GameNode> {
116         private Board boardValue;
117         private GameNode prev;
118         private int moves;
119         private boolean isTwin;
120 
121         public GameNode(Board current, GameNode prev, int moves, boolean isTwin) {
122             this.boardValue = current;
123             this.prev = prev;
124             this.moves = moves;
125             this.isTwin = isTwin;
126         }
127 
128         public int compareTo(GameNode that) {
129             int priority1 = this.boardValue.manhattan() + this.moves;
130             int priority2 = that.boardValue.manhattan() + that.moves;
131 
132             if (priority1 == priority2) {
133                 return 0;
134             } else if (priority1 > priority2) {
135                 return 1;
136             } else {
137                 return -1;
138             }
139         }
140     }
141 }
Solver
原文地址:https://www.cnblogs.com/enigmaxp/p/5913488.html