一、题意

经典的八数码问题,有人说不做此题人生不完整,哈哈。给出一个含数字1~8和字母x的3 * 3矩阵,如:

1  2  X

           3 4  6

           7  5  8

现在要你移动x的位置(方向为上、下、左、右),使得这个矩阵为:

1  2  3 

           4  5  6

           7  8 x

求出最后能得到这个解的移动方案,输出移动的操作。(不要求最优解,也就是不要求移动次数最少)

二、题解

这个8数码问题,我们可以把它看成是一个全排列,从一个初始的排列通过移动元素的位置,到达最终的123456789的这种排列,这里的X我们用9代替。

我们知道X有四个选择移动的方向,但是不一定有四个,如果在左上角就只能右移和下移了,还有很多种限制情况。由于数组是从0开始的,所以他的下标应该是:

0  1  2

3  4  5

6  7  8

if( id % 3 != 2)如果id不是2,5,8就可以向右移动;

     if (id % 3 != 0) 如果id不是0,3,6就可以向左移动;

     if( id > 2 ) 如果id大于2就可以向上移动;

     if( id < 6)  如果id小于6就可以向下移动。

     现在我们有了移动的方向了,但是我们知道可能这些选择中包含着以前就走过的状态。那怎么办来避免已经访问过的状态呢,这就用到了把全排列转换成数字的hash函数(这里其实还可以用康托展开),每一个排列都能对应一个数字,如果这个数字出现过就不访问。这可以用一个Boolean数组实现。

这个hash函数的原理用到了变进制和序数对的知识,详细信息请参考:http://blog.sina.com.cn/s/blog_6635898a0100p4re.html

接下来就要用到BFS来找到状态转换路径了,每一个状态用一个类表示,包括前一个状态到本状态的操作本状态的数本状态X所处位置索引前一个状态的hash值

遍历每个状态从0开始,记录可以到达的状态(一次最多可以到达四个),直到num=123456789。例如,0可以到1、2、3,而1可以到4、5,2可以到6、7,...并用

q[tail].pre = head记录之前的的结点,这样到最后的最终结点往前遍历就可以了。q[tail].op = op记录了操作,输出操作就可以了。这就相当于找到了一条路径,路径上的结点记录了到这一步的操作,输出操作就行了。但想之前所说的,这不一定是最优解,这是最快到达的,不一定是操作最少的。

三、java代码

import java.util.Scanner;

class Status{
char operation;
int number, index, previous;
} public class Main{
static int Max = 363000; //总得状态数量, 9!=362880
static Status[] q=new Status[Max];
static int head;
static int tail;
static int factorial[] = {1,1,2,6,24,120,720,5040,40320};
static int Pow[] = {100000000,10000000,1000000,100000,10000,1000,100,10,1};
static boolean[] vis=new boolean[Max];
// 全排列的hash函数。
static int permutationToNumberHash(int num){
int i, j;
int[] n=new int[10];
for(i = 0; i < 9; i ++){
n[i] = num % 10;
num /= 10;
}
int c, key = 0;
for(i = 1; i < 9; i ++){
for(c = 0, j = 0; j < i; j ++)
if(n[j] < n[i])
c ++;
key += c * factorial[i];
}
return key;
} static void exchangeLocation(int num, int a, int b, char op){ // 操作:第a个数和第b个数交换。
int n1, n2;
n1 = num / Pow[a] % 10;
n2 = num / Pow[b] % 10;
num = num - (n1-n2)*Pow[a] + (n1-n2)*Pow[b]; //移动后的数字大小
int key = permutationToNumberHash(num);
if(!vis[key]){
vis[key] = true;
q[tail].operation = op;
q[tail].number = num;
q[tail].previous = head;
q[tail ++].index = b;
}
} static void output(int k){
if(q[k].operation != 0){
output(q[k].previous);
System.out.print( q[k].operation);
}
}
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int i, num, id , t;
char c;
id=-1;
//读入数据,用9代替x,用一个十进制数表示读入数据。
for(num = i = 0; i < 9; i ++){
c=sc.next().charAt(0);
if(c == 'x'){
t = 9;
id = i;
}else
t = c - '0';
num = 10 * num + t;//顺序存储
}
//初始化每一个状态
for(i=0;i<Max;i++){
q[i]=new Status();
}
boolean flag = false;
head = 0;
tail = 1;
//q[0]表示x所在的的id和状态数
q[0].index = id;
q[0].number = num;
//广度搜索找出一条路径,最后的数是123456789.
/*具体实现:
* 遍历每个状态从0开始,记录可以到达的状态(一次最多可以到达四个)。直到num=123456789。
* 例如,0可以到1、2、3,而1可以到4、5,2可以到6、7,...并用 q[tail].pre = head记录之前的的结点,这样到最后
* 的最终结点往前遍历就可以了。q[tail].op = op记录了操作,输出操作就可以了。
* */
while(tail > head && !flag){
int cnt = tail - head;
while(cnt --!=0){
num = q[head].number;
if(num == 123456789){
flag = true;
break;
}
id = q[head].index;
//注意这里的移动方向是指数的移动方向,不是X的移动方向
//还有id的范围是0~8
/* 0 1 2
* 3 4 5
* 6 7 8
*/
if(id % 3 != 2) //如果id不是2,5,8就可以向右移动
exchangeLocation(num, id, id + 1, 'r');
if(id % 3 != 0) //如果id不是0,3,6就可以向左移动
exchangeLocation(num, id, id - 1, 'l');
if(id > 2) //如果id大于2就可以向上移动
exchangeLocation(num, id, id - 3, 'u');
if(id < 6) //如果id小于6就可以向下移动
exchangeLocation(num, id, id + 3, 'd');
head ++;
}
}
if(flag)
output(head);
else
System.out.println("unsolvable");
}
}

参考:http://blog.sina.com.cn/s/blog_6635898a0100p4sx.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

Poj 1077 eight(BFS+全序列Hash解八数码问题)的更多相关文章

  1. hdu 1043 pku poj 1077 Eight (BFS + 康拓展开)

    http://acm.hdu.edu.cn/showproblem.php?pid=1043 http://poj.org/problem?id=1077 Eight Time Limit: 1000 ...

  2. 【算法】BFS+哈希解决八数码问题

    15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...

  3. 【基础练习】【BFS+A*】codevs1225八数码难题题解

    题目描写叙述 Description Yours和zero在研究A*启示式算法.拿到一道经典的A*问题,可是他们不会做,请你帮他们. 问题描写叙述 在3×3的棋盘上,摆有八个棋子,每一个棋子上标有1至 ...

  4. ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

    八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...

  5. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

  6. POJ 1077 Eight (BFS+康托展开)详解

    本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...

  7. HDU 1043 & POJ 1077 Eight(康托展开+BFS+预处理)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  8. HDU 1043 & POJ 1077 Eight(康托展开+BFS | IDA*)

    Eight Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30176   Accepted: 13119   Special ...

  9. Eight POJ - 1077 HDU - 1043 八数码

    Eight POJ - 1077 HDU - 1043 八数码问题.用hash(康托展开)判重 bfs(TLE) #include<cstdio> #include<iostream ...

随机推荐

  1. POJ 2187 Beauty Contest【凸包周长】

    题目: http://poj.org/problem?id=1113 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...

  2. 九度OJ 1326:Waiting in Line(排队) (模拟)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:220 解决:64 题目描述: Suppose a bank has N windows open for service. There is ...

  3. 九度OJ 1208:10进制 VS 2进制 (进制转换)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2040 解决:612 题目描述: 对于一个十进制数A,将A转换为二进制数,然后按位逆序排列,再转换为十进制数B,我们乘B为A的二进制逆序数. ...

  4. Convex combination

    en.wikipedia.org/wiki/Convex_combination 凸组合 In convex geometry, a convex combination is a linear co ...

  5. can t connect to mysql server on 'localhost'解决方法

    源:http://www.111cn.net/database/mysql/37700.htm 先重启服务器可解决大部分问题 错误编号:2003 问题分析: 无法连接到 mysql 服务器,可能的情况 ...

  6. 私有云的迁移:从VMware到OpenStack

    VMware和OpenStack经常被描述为相互竞争的两种私有云技术.虽然这两种技术其实可以互补,但一些组织却选择从VMware迁移到OpenStack的私有云上. 让我们来看看这些组织如何能同时使用 ...

  7. 用Pythonic方式来思考

    一门语言的编程习惯是由用户来确立的.这些年来,Python开发者用Pythonic这个形容词来描述那种符合特定风格的代码. 这种Pyhtonic风格,既不是严密的规范,也不是由编译器强加给开发者的规则 ...

  8. 图片oom问题

    1.什么是OOM? 程序申请内存过大,虚拟机无法满足我们,然后自杀了.这个现象通常出现在大图片的APP开发,或者需要用到很多图片的时候.通俗来讲就是我们的APP需要申请一块内存来存放图片的时候,系统认 ...

  9. 【leetcode刷题笔记】Remove Duplicates from Sorted List

    Given a sorted linked list, delete all duplicates such that each element appear only once. For examp ...

  10. 【leetcode刷题笔记】Next Permutation

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...