照着API写即可。注意每次调用twin()都要返回相同的值,即twin()只能交换两个固定位置的数字。
import edu.princeton.cs.algs4.StdRandom;
import java.util.ArrayList;
import java.util.List;
public class Board {
private final int size;
private int[][] tiles;
// create a board from an n-by-n array of tiles,
// where tiles[row][col] = tile at (row, col)
public Board(int[][] tiles) {
size = tiles[0].length;
// 注意需要拷贝而不是直接引用,不然所有的Board对象使用的都是同一个二维数组
this.tiles = new int[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
this.tiles[i][j] = tiles[i][j];
}
}
}
// string representation of this board
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(size + "\n");
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (j == 0) {
sb.append(tiles[i][j]);
} else {
sb.append(" " + tiles[i][j]);
}
}
sb.append("\n");
}
return sb.toString();
}
// board dimension n
public int dimension() {
return size;
}
// number of tiles out of place
public int hamming() {
int count = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (i == size - 1 && j == size - 1) {
break;
}
if (tiles[i][j] != i * size + j + 1) {
count++;
}
}
}
return count;
}
// sum of Manhattan distances between tiles and goal
public int manhattan() {
int sum = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (tiles[i][j] != 0 && tiles[i][j] != i * size + j + 1) {
int ii = (tiles[i][j] - 1) / size;
int jj = (tiles[i][j] - 1) % size;
sum += Math.abs(ii - i) + Math.abs(jj - j);
}
}
}
return sum;
}
// is this board the goal board?
public boolean isGoal() {
return hamming() == 0;
}
// does this board equal y?
public boolean equals(Object y) {
if (y == null) {
return false;
}
if (y == this) {
return true;
}
if (this.getClass().isInstance(y)) {
Board that = (Board) y;
if (this.size != that.size) {
return false;
}
for (int i = 0; i < this.size; i++) {
for (int j = 0; j < this.size; j++) {
if (this.tiles[i][j] != that.tiles[i][j]) {
return false;
}
}
}
return true;
} else {
return false;
}
}
// all neighboring boards
public Iterable<Board> neighbors() {
List<Board> neighbors = new ArrayList<>();
int blankI = 0, blankJ = 0;
OUTER:
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (tiles[i][j] == 0) {
blankI = i;
blankJ = j;
break OUTER;
}
}
}
if (blankI > 0) {
Board up = new Board(tiles);
up.swap(blankI, blankJ, blankI - 1, blankJ);
neighbors.add(up);
}
if (blankI < size - 1) {
Board down = new Board(tiles);
down.swap(blankI, blankJ, blankI + 1, blankJ);
neighbors.add(down);
}
if (blankJ > 0) {
Board left = new Board(tiles);
left.swap(blankI, blankJ, blankI, blankJ - 1);
neighbors.add(left);
}
if (blankJ < size - 1) {
Board right = new Board(tiles);
right.swap(blankI, blankJ, blankI, blankJ + 1);
neighbors.add(right);
}
return neighbors;
}
// a board that is obtained by exchanging any pair of tiles
public Board twin() {
Board twin = new Board(tiles);
int i = 0, j = 1, m = 1, n = 0;
while (tiles[i][j] == 0) {
i++;
}
while (tiles[m][n] == 0) {
n++;
}
twin.swap(i, j, m, n);
return twin;
}
private void swap(int i, int j, int m, int n) {
int temp = tiles[i][j];
tiles[i][j] = tiles[m][n];
tiles[m][n] = temp;
}
// unit testing (not graded)
public static void main(String[] args) {
int[][] test = {{0, 1, 3}, {4, 2, 5}, {7, 8, 6}};
Board board = new Board(test);
System.out.println(board);
for (Board b : board.neighbors()) {
System.out.println(b);
}
System.out.println(board.twin());
System.out.println(board.manhattan());
}
}
对于是否有解法的判断:同时处理两个数组,一个是原数组,另一个是原数组调用twin()后的数组,两数组中只要确定一个有解法,那另一个就没有解法。
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.MinPQ;
import edu.princeton.cs.algs4.StdOut;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Solver {
private Node cur;
// find a solution to the initial board (using the A* algorithm)
public Solver(Board initial) {
if (initial == null) {
throw new IllegalArgumentException();
}
MinPQ<Node> pq = new MinPQ<>();
MinPQ<Node> pqTwin = new MinPQ<>();
pq.insert(new Node(initial, null));
pqTwin.insert(new Node(initial.twin(), null));
while (true) {
cur = pq.delMin();
if (cur.isGoal()) {
break;
}
insertNeighbors(pq, cur);
Node curTwin = pqTwin.delMin();
if (curTwin.isGoal()) {
break;
}
insertNeighbors(pqTwin, curTwin);
}
}
// is the initial board solvable? (see below)
public boolean isSolvable() {
return cur.isGoal();
}
// min number of moves to solve initial board
public int moves() {
if (isSolvable()) {
return cur.moves;
} else {
return -1;
}
}
// sequence of boards in a shortest solution
public Iterable<Board> solution() {
if (isSolvable()) {
List<Board> path = new ArrayList<>();
Node temp = cur;
while (temp != null) {
path.add(temp.board);
temp = temp.prev;
}
Collections.reverse(path);
return path;
} else {
return null;
}
}
private void insertNeighbors(MinPQ<Node> pq, Node node) {
for (Board neighbor : node.getNeighbors()) {
if (node.prev == null || !neighbor.equals(node.prev.board)) {
pq.insert(new Node(neighbor, node));
}
}
}
private class Node implements Comparable<Node> {
private final Node prev;
private final Board board;
private final int moves;
private final int manhattan;
private final int priority;
public Node(Board board, Node prev) {
this.board = board;
this.prev = prev;
manhattan = board.manhattan();
moves = prev == null ? 0 : prev.moves + 1;
priority = manhattan + moves;
}
public Iterable<Board> getNeighbors() {
return board.neighbors();
}
public boolean isGoal() {
return board.isGoal();
}
@Override
public String toString() {
return board.toString();
}
@Override
public int compareTo(Node that) {
return this.priority - that.priority;
}
}
// 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);
}
}
}
cnblogs - evasean
A*算法详解