题意理解
求解8puzzle游戏, 使用A*算法。
问题分析
这个用到了优先级队列,堆排序。但是作业太难了。把A*算法融进来,把树结构融进来。树结构的存储模式是双亲表示法。优先级队列就看起来太简单了。得分97分。
其他
参考https://www.cnblogs.com/evasean/p/7281901.html
链接
/* *****************************************************************************
* Name:
* Date:
* Description:
**************************************************************************** */
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.StdOut;
public class Board {
private int[][] boardValue;
private final int dim;
// create a board from an n-by-n array of tiles,
// where tiles[row][col] = tile at (row, col)
public Board(int[][] tiles) {
dim = tiles.length;
boardValue = new int[dim][dim];
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
boardValue[i][j] = tiles[i][j];
}
}
}
// string representation of this board
public String toString() {
StringBuilder s = new StringBuilder();
s.append(dim + "\n");
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
s.append(String.format("%2d ", boardValue[i][j]));
}
s.append("\n");
}
return s.toString();
}
// board dimension n
public int dimension() {
return dim;
}
// number of tiles out of place
public int hamming() {
int dis = 0;
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
if (boardValue[i][j] != 0 && boardValue[i][j] != i * dim + j + 1) {
dis ++;
}
}
}
return dis;
}
// sum of Manhattan distances between tiles and goal
public int manhattan() {
int dis = 0;
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
if (boardValue[i][j] != 0) {
int value = boardValue[i][j];
int row_target = (value - 1) / dim;
int col_target = (value - 1) % dim;
int curr_dis = Math.abs(i - row_target) + Math.abs(j - col_target);
dis += curr_dis;
}
}
}
return dis;
}
// is this board the goal board?
public boolean isGoal() {
if (this.hamming() == 0) {
return true;
}
return false;
}
// 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 target = (Board) y;
if (this.dimension() != target.dimension()) {
return false;
}
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
if (this.boardValue[i][j] != target.boardValue[i][j]) {
return false;
}
}
}
return true;
}
// all neighboring boards
public Iterable neighbors() {
int zeroRow = -1;
int zeroCol = -1;
int[][] clones = new int[dim][dim];
//find zero postion
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
if (boardValue[i][j] == 0) {
zeroRow = i;
zeroCol = j;
}
clones[i][j]= boardValue[i][j];
}
}
//StdOut.println("zeroRow=" + zeroRow + ";zeroCol=" + zeroCol);
Stack neighbors = new Stack();
if (zeroRow - 1 >= 0) { //left
clones[zeroRow][zeroCol] = clones[zeroRow - 1][zeroCol];
clones[zeroRow - 1][zeroCol] = 0;
neighbors.push(new Board(clones));
clones[zeroRow - 1][zeroCol] = clones[zeroRow][zeroCol];
clones[zeroRow][zeroCol] = 0;
}
if (zeroRow + 1 <= dim - 1) {
clones[zeroRow][zeroCol] = clones[zeroRow + 1][zeroCol];
clones[zeroRow + 1][zeroCol] = 0;
neighbors.push(new Board(clones));
clones[zeroRow + 1][zeroCol] = clones[zeroRow][zeroCol];
clones[zeroRow][zeroCol] = 0;
}
if (zeroCol - 1 >= 0) {
clones[zeroRow][zeroCol] = clones[zeroRow][zeroCol - 1];
clones[zeroRow][zeroCol - 1] = 0;
neighbors.push(new Board(clones));
clones[zeroRow][zeroCol - 1] = clones[zeroRow][zeroCol];
clones[zeroRow][zeroCol] = 0;
}
if (zeroCol + 1 <= dim - 1) {
clones[zeroRow][zeroCol] = clones[zeroRow][zeroCol + 1];
clones[zeroRow][zeroCol + 1] = 0;
neighbors.push(new Board(clones));
clones[zeroRow][zeroCol + 1] = clones[zeroRow][zeroCol];
clones[zeroRow][zeroCol] = 0;
}
return neighbors;
}
// a board that is obtained by exchanging any pair of tiles
public Board twin() {
Board twinBoard = this;
int row = 0;
int col = 0;
if (twinBoard.boardValue[0][0] == 0) {
col = 1;
}
for (int i = 0; i < dim; i++) {
for (int j = 0; j < dim; j++) {
if (twinBoard.boardValue[i][j] != twinBoard.boardValue[row][col] &&
twinBoard.boardValue[i][j] != 0) {
int tmp = twinBoard.boardValue[i][j];
twinBoard.boardValue[i][j] = twinBoard.boardValue[row][col];
twinBoard.boardValue[row][col] = tmp;
return twinBoard;
}
}
}
return this;
}
public static void main(String[] args) {
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 board = new Board(tiles);
StdOut.println(board.toString());
StdOut.println(board.dimension());
StdOut.println(board.hamming());
StdOut.println(board.manhattan());
for (Board neighbor : board.neighbors()) {
StdOut.println(neighbor);
}
StdOut.println(board.isGoal());
}
}
/* *****************************************************************************
* Name:
* Date:
* Description:
**************************************************************************** */
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.Stack;
import edu.princeton.cs.algs4.StdOut;
public class Solver {
private SearchNode currentNode; //input
private SearchNode twinCurrentNode; //tuning
private Stack solution; //output
// find a solution to the initial board (using the A* algorithm)
public Solver(Board initial) {
if (initial == null) {
throw new IllegalArgumentException();
}
currentNode = new SearchNode(initial,null);
twinCurrentNode = new SearchNode(initial.twin(), null);
MinPQ priorityQueue = new MinPQ();
MinPQ twinPriorityQueue = new MinPQ();
priorityQueue.insert(currentNode);
twinPriorityQueue.insert(twinCurrentNode);
while (true) {
currentNode = priorityQueue.delMin();
if(currentNode.currentBoard.isGoal()) {
break;
}
Iterable neighbors = currentNode.currentBoard.neighbors();
for(Board neighbor : neighbors) {
if (currentNode.preSearchNode == null ||
!neighbor.equals(currentNode.preSearchNode.currentBoard)) {
priorityQueue.insert(new SearchNode(neighbor, currentNode));
}
}
twinCurrentNode = twinPriorityQueue.delMin();
if(twinCurrentNode.currentBoard.isGoal()) {
break;
}
Iterable twinNeighbors = twinCurrentNode.currentBoard.neighbors();
for(Board twinNeighbor : twinNeighbors) {
if (twinCurrentNode.preSearchNode == null ||
!twinNeighbor.equals(twinCurrentNode.preSearchNode.currentBoard)) {
twinPriorityQueue.insert(new SearchNode(twinNeighbor, twinCurrentNode));
}
}
}
}
private class SearchNode implements Comparable {
public Board currentBoard;
public SearchNode preSearchNode;
public int moves;
public int priority;
public SearchNode(Board myCurrentBoard, SearchNode myPreSearchNode) {
currentBoard = myCurrentBoard;
preSearchNode = myPreSearchNode;
if (myPreSearchNode == null) {
moves = 0;
}
else {
moves = myPreSearchNode.moves + 1;
}
priority = moves + currentBoard.manhattan();
}
@Override
public int compareTo(SearchNode o) {
return Integer.compare(this.priority, o.priority);
}
}
// is the initial board solvable? (see below)
public boolean isSolvable() {
return currentNode.currentBoard.isGoal();
}
// min number of moves to solve initial board
public int moves() {
if (currentNode.currentBoard.isGoal()) {
return currentNode.moves;
}
else {
return -1;
}
}
// sequence of boards in a shortest solution
public Iterable solution() {
if (currentNode.currentBoard.isGoal()) {
solution = new Stack();
SearchNode node = currentNode;
while (node != null) {
solution.push(node.currentBoard);
node = node.preSearchNode;
}
return solution;
}
else {
return null;
}
}
// 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);
}
}
}