Programming Assignment 4: 8 Puzzle
The Problem. 求解8数码问题。用最少的移动次数能使8数码还原.
Best-first search.使用A*算法来解决,我们定义一个Seach Node,它是当前搜索局面的一种状态,记录了从初始到达当前状态的移动次数和上一个状态。初始化时候,当前状态移动次数为0,上一个状态为null,将其放入优先级队列,通过不断的从优先级队列中取出Seach Node去扩展下一级的状态,直到找到目标状态。对于优先级队列中优先级的定义我们可以采用:Hamming priority function 和 Manhattan priority function,第一个表示有多少个块不在目标位置,第二个表示每一个块到他所在目标位置曼哈顿距离之和。
对于解决8数码来说,为了寻求最少步数,那么当前状态移动步数优先级需要考虑,同时选择Hamming或者Manhattan进行启发式的搜索。当目标状态出现时,我们就是使用了最少的步数。怎么证明?
A critical optimization.在搜索的过程中会遇到重复出现的状态,所以我们在进行下一个状态搜索的时候,判断不要将它相邻已经出现的状态加入到优先级队列中。
Game Tree. 搜索是一个博弈树的形式展开,每一个节点对应一个状态,树根是初始状态,在每一步中,A*算法删除优先级对联中priority最小的那个节点,然后进行处理
Detecting infeasible puzzles. 有些初始状态是无法通过移动来得到目标状态的,比如:
但是我们通过交换任意行不为空白的相邻的两个,如果按照这个初始状态来进行搜索,我们就可以得到目标状态。对于可行性的判断,可以根据初始状态和目标状态逆序数的奇偶性来进行判断,在进行移动后,应该奇偶性保持一致。但在这次Assignment中,不要求这么做,而是通过加入两个初始节点,一个是原有的,一个是进行相邻交换一次的,同时进行A*的搜索,如果原有的找到了目标解,那么就是可行,否则另一个找到了可行解,原有的就是不可行状态。
同一个初始状态到目标状态的最小移动次数是存在多解。其他还有IDA*,双向BFS等解法。
一些优化的地方,使用char[][] 比int[][]的空间更小。在进行曼哈顿距离求解的时候,我们可以用空间换时间,预存每个数字的曼哈顿距离,然后直接返回。
8数码是一个NP-Hard问题,没有有效的解存在。
完整的代码如下:
Board.java
public class Board {
private int[][] matrix; // blocks
private int N; // deimension
private int posX, posY; // 0' position
// 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;
matrix = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
matrix[i][j] = blocks[i][j];
if (matrix[i][j] == 0) {
posX = i;
posY = j;
}
}
}
}
// board dimension N
public int dimension() {
return N;
}
// number of blocks out of place
public int hamming() {
int hammingDis = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (matrix[i][j] == 0) continue;
if (i*N+j+1 != matrix[i][j]) hammingDis++;
}
}
return hammingDis;
}
// sum of Manhattan distances between blocks and goal
public int manhattan() {
int manhattanDis = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (matrix[i][j] == 0) continue;
int x, y;
if (matrix[i][j] % N == 0) {
x = matrix[i][j] / N - 1;
y = N - 1;
} else {
x = matrix[i][j] / N;
y = matrix[i][j] % N - 1;
}
manhattanDis += Math.abs(i-x) + Math.abs(j-y);
}
}
return manhattanDis;
}
// is this board the goal board?
public boolean isGoal() {
if (posX != N-1 || posY != N-1) return false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (matrix[i][j] == 0) continue;
if (i*N+j+1 != matrix[i][j]) return false;
}
}
return true;
}
// a board obtained by exchanging two adjacent blocks in the same row
public Board twin() {
int x = -1, y = -1;
int[][] tmpBlock = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (j < N-1 && matrix[i][j] != 0 && matrix[i][j+1] != 0) {
x = i;
y = j;
}
tmpBlock[i][j] = matrix[i][j];
}
}
if (x == -1 && y == -1) throw new IllegalArgumentException();
int t = tmpBlock[x][y];
tmpBlock[x][y] = tmpBlock[x][y+1];
tmpBlock[x][y+1] = t;
return new Board(tmpBlock);
}
// 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 that = (Board) y;
if (this.dimension() != that.dimension()) return false;
int sz = this.dimension();
for (int i = 0; i < sz; i++) {
for (int j = 0; j < sz; j++) {
if (this.matrix[i][j] != that.matrix[i][j])
return false;
}
}
return true;
}
// all neighboring boards
public Iterable<Board> neighbors() {
Queue<Board> queue = new Queue<Board>();
int[] dx = {0, 0, -1, 1};
int[] dy = {1, -1, 0, 0};
for (int i = 0; i < 4; i++) {
int x = posX + dx[i];
int y = posY + dy[i];
if (x < N && x >= 0 && y < N && y >= 0) {
int tmp = matrix[posX][posY];
matrix[posX][posY] = matrix[x][y];
matrix[x][y] = tmp;
queue.enqueue(new Board(matrix));
tmp = matrix[posX][posY];
matrix[posX][posY] = matrix[x][y];
matrix[x][y] = tmp;
}
}
return queue;
}
// 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 ", matrix[i][j]));
}
s.append("\n");
}
return s.toString();
}
public static void main(String[] args) {
int[][] mat = {
{1, 2, 3},
{4, 6, 0},
{7, 8, 5}
};
//hamming
//manhattan
Board b = new Board(mat);
Board c = b.twin().twin();
StdOut.println(b.equals(c));
StdOut.print(b.toString());
for (Board it : b.neighbors()) {
StdOut.print(it.toString());
StdOut.println("hamming: " + it.hamming());
StdOut.println("manhattan: " + it.manhattan());
}
}
}
Solver.java
public class Solver {
private BoardNode targetBoardNode; // record targetBoardNode
private class BoardNode implements Comparable<BoardNode> {
private Board item;
private BoardNode prev;
private int move;
private boolean isTwin;
// compare by priority
public int compareTo(BoardNode that) {
if (that == null)
throw new NullPointerException("Input argument is null");
int thisPriority = this.move + this.item.manhattan();
int thatPriority = that.move + that.item.manhattan();
if (thisPriority < thatPriority)
return -1;
else if (thisPriority == thatPriority)
return 0;
else
return 1;
}
}
// find a solution to the initial board (using the A* algorithm)
public Solver(Board initial) {
targetBoardNode = null;
// priority queue maintain the minimum elements
MinPQ<BoardNode> minpq = new MinPQ<BoardNode>();
// initial boardnode
BoardNode bn = new BoardNode();
bn.item = initial;
bn.prev = null;
bn.move = 0;
bn.isTwin = false;
minpq.insert(bn);
// initial twin boardnode
BoardNode twinbn = new BoardNode();
twinbn.item = initial.twin();
twinbn.prev = null;
twinbn.move = 0;
twinbn.isTwin = true;
minpq.insert(twinbn);
while (!minpq.isEmpty()) {
BoardNode curbn = minpq.delMin();
if (curbn.item.isGoal()) {
if (curbn.isTwin) targetBoardNode = null;
else targetBoardNode = curbn;
break;
}
for (Board it : curbn.item.neighbors()) {
if (curbn.prev == null || !curbn.prev.item.equals(it)) {
bn = new BoardNode();
bn.item = it;
bn.prev = curbn;
bn.move = curbn.move+1;
if (curbn.isTwin)
bn.isTwin = true;
else
bn.isTwin = false;
minpq.insert(bn);
}
}
}
}
// is the initial board solvable?
public boolean isSolvable() {
return targetBoardNode != null;
}
// min number of moves to solve initial board; -1 if no solution
public int moves() {
if (isSolvable())
return targetBoardNode.move;
else
return -1;
}
// sequence of boards in a shortest solution; null if no solution
public Iterable<Board> solution() {
Stack<Board> stack = new Stack<Board>();
BoardNode tmpbn = targetBoardNode;
while (tmpbn != null) {
stack.push(tmpbn.item);
tmpbn = tmpbn.prev;
}
if (stack.isEmpty())
return null;
else
return stack;
}
// solve a slider puzzle (given below)
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);
}
}
}
Programming Assignment 4: 8 Puzzle的更多相关文章
- Coursera Algorithms Programming Assignment 4: 8 Puzzle (100分)
题目原文:http://coursera.cs.princeton.edu/algs4/assignments/8puzzle.html 题目要求:设计一个程序解决8 puzzle问题以及该问题的推广 ...
- 课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 3.Programming Assignment : Planar data classification with a hidden layer
Planar data classification with a hidden layer Welcome to the second programming exercise of the dee ...
- Algorithms: Design and Analysis, Part 1 - Programming Assignment #1
自我总结: 1.编程的思维不够,虽然分析有哪些需要的函数,但是不能比较好的汇总整合 2.写代码能力,容易挫败感,经常有bug,很烦心,耐心不够好 题目: In this programming ass ...
- Algorithms : Programming Assignment 3: Pattern Recognition
Programming Assignment 3: Pattern Recognition 1.题目重述 原题目:Programming Assignment 3: Pattern Recogniti ...
- Programming Assignment 2: Randomized Queues and Deques
实现一个泛型的双端队列和随机化队列,用数组和链表的方式实现基本数据结构,主要介绍了泛型和迭代器. Dequeue. 实现一个双端队列,它是栈和队列的升级版,支持首尾两端的插入和删除.Deque的API ...
- 课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)
Please note that when you are working on the programming exercise you will find comments that say &q ...
- Programming Assignment 5: Kd-Trees
用2d-tree数据结构实现在2维矩形区域内的高效的range search 和 nearest neighbor search.2d-tree有许多的应用,在天体分类.计算机动画.神经网络加速.数据 ...
- coursera普林斯顿算法课part1里Programming Assignment 2最后的extra challenge
先附上challenge要求: 博主最近在刷coursera普林斯顿大学算法课part1部分的作业,Programming Assignment2最后的这个extra challenge当初想了一段时 ...
- Programming Assignment 2: Deques and Randomized Queues
编程作业二 作业链接:Deques and Randomized Queues & Checklist 我的代码:Deque.java & RandomizedQueue.java & ...
随机推荐
- zhuang 定制iOS 7中的导航栏和状态栏
近期,跟大多数开发者一样,我也正忙于对程序进行升级以适配iOS 7.最新的iOS 7外观上有大量的改动.从开发者的角度来看,导航栏和状态栏就发生了明显的变化.状态栏现在是半透明的了,这也就意味着导航栏 ...
- Flex 加载 wmf,svg
最近做gis系统发现要在flex加载wmf图片.我记得flash的loader只能是png,gis,jpg.wmf格式居然是window出的,flash居然不支持我也是醉了,没办法,只能后台转格式,首 ...
- Android软件更新安装。
app的开发有一个问题是避免不了的,那就是软件的升级维护. 这里我在查过一些资料和写了一个升级帮助类.使用很方便.直接导入就可以了. ( VersionBean.class为更新地址返回的数据对象,我 ...
- android WebView问题
1.加载本地js.css文件 今天碰到个问题,使用WebView加载html数据,本来没什么问题,loadUrl(),loadData(),都可以使用 但是如果需要引入本地的js.css文件就碰到问题 ...
- 基于boa服务器的web控制mini2440的GPIO口
win7 系统 虚拟机:ubuntu12.04 开发板:mini2440 上一篇已经详细的讲解了如何配置boa服务器,在这里我们就要利用boa服务器带来的便利,利用web控制开发板上的GIPO口,这 ...
- openldap主机访问控制(基于hostname)
http://mayiwei.com/2013/03/21/centos6-openldap/ http://www.zytrax.com/books/ldap/ch11/dynamic.html h ...
- Android开发--环境的配置
一 Android开发环境:JDK.eclipse ADT.海马模拟器或者夜神模拟器.配置之前先保证运行内存足够大,不然会导致运行卡. 二 JDK(不用安装) 1.jdk官方下载地址:http://w ...
- Inside The C++ Object Model - 01
前言 1.Foundation项目是一个定义大系统开发模型的项目,又叫Grail. 2.Grail中编译器被分为:parser(语法分析)->type checking -> simpli ...
- ApexSql Log 2014.04.1133破解版&补丁
已上传最新的2016版本,请移步: http://www.cnblogs.com/gsyifan/p/ApexSql_Log_2016_Crack.html 状态不好,鬼使补差的跑到服务器上updat ...
- Redmine2.5+CentOS6+Apache2
redmine是使用ruby开发的一款无任何商业限制且可自行部署的项目管理软件,其简洁的界面比较符合程序猿的定位,使用起来比较方便,由于我之前装3X没 成功,各版本之间的依存和配置都不一样,所以最后参 ...