Eight

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10101    Accepted Submission(s): 2684
Special Judge

Problem Description
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:

 1  2  3  4
5 6 7 8
9 10 11 12
13 14 15 x

where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:

 1  2  3  4     1  2  3  4     1  2  3  4     1  2  3  4
5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
r-> d-> r->

The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.

Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and 
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).

In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three 
arrangement.

 
Input
You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle

1 2 3 
x 4 6 
7 5 8

is described by this list:

1 2 3 x 4 6 7 5 8

 
Output
You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
 
Sample Input
2 3 4 1 5 x 7 6 8
 
Sample Output
ullddrurdllurdruldr
 
#include <iostream>
#include <string>
#include <string.h>
#include <map>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <vector>
#include <math.h>
#include <set>
#define Max(a,b) ((a)>(b)?(a):(b))
#pragma comment(linker, "/STACK:16777216")
using namespace std ;
typedef long long LL ;
const int fac[] = {,,,,,,,,} ;
const int d[][] = {{,},{-,},{,},{,-}} ; //四个方向
const char direction[] = {'d','u','r','l'} ; //输出记录
const int end_pos[][] = {{,},{,},{,},{,},
{,},{,},{,},
{,},{,},{,}} ; //最后状态 123
// 456
// 78X class Node{
public :
char mat[][] ;
int x ;
int y ;
int h ; //h(x)=递归层数
int g ; //g(x)=曼哈顿距离和
int f ; //估价函数 f(x) = g(x)+ h(x)
int id ; //hash值,用于判重,利用排列序列的康拓展开
int G() ;//求g(x)
int cango() ; //剪枝,为什么逆序数必须是偶数,网上很多人问这个问题。
//我的解答: 与X(空白)交换的Y ,编号(index)相差为偶数,即在[ index[X] + 1 .index[Y]-1 ] 区间的数为偶数 ;
// 交换前 ,设 [ index[X] + 1 .index[Y]-1 ](zh) ,〉Y有a个,<Y 有b个 ,则a+b为偶数 ;
// 交换后 ,逆序数相较之前 +b -a ,即| 逆序数交换前 -逆序数交换后 | 为偶数 。
// 也就是说无论何种交换,逆序数的变化差值为偶数 ,而最终的状态12345678X 。 (X可看作为9) ,逆序数为0。
// 即只能从逆序数为偶数的状态转移 。
int Hash() ; // 求id
void out() ;
Node(){};
Node(vector<char>) ;
friend bool operator < (const Node &A ,const Node &B){
if(A.f != B.f)
return A.f > B.f ;
else
return A.g > B.g ;
} //建堆,使用C++ STL 优先队列 ,f(x)=g(x)+h(x) , f(x)小的优先级别大,也就是说与最后的状态差异小的优先考虑
}; Node::Node(vector<char>s){
int i , j ;
for(int k = ;k < s.size() ;k++){
i = k/ ;
j = k% ;
if(s[k] == 'x'){
this->x = i ;
this->y = j ;
}
mat[i][j] = s[k] ;
}
} int Node::G(){
int sum = ;
for(int i = ;i <= ;i++){
for(int j = ;j <= ;j++){
if(mat[i][j]=='x')
continue ;
int n = mat[i][j] - '' ;
sum = sum + abs(i-end_pos[n][]) + abs(j - end_pos[n][]) ;
}
}
return sum ;
} int Node::cango(){
char num[] ;
int n = ,sum = ;
for(int i = ;i <= ;i++){
for(int j = ;j <= ;j++){
if(mat[i][j] != 'x')
num[++n] = mat[i][j] ;
}
}
for(int i = ;i <= n ;i++){
for(int j = ;j < i ;j++){
if(num[j] > num[i])
sum++ ;
}
}
return (sum&) == ;
} int Node::Hash(){
char num[] ;
int n = ,sum ,index = ;
for(int i = ;i <= ;i++){
for(int j = ;j <= ;j++)
num[n++] = mat[i][j] ;
}
for(int i = ;i < n ;i++){
sum = ;
for(int j = ;j < i ;j++){
if(num[j] > num[i])
sum++ ;
}
index += fac[i]*sum ;
}
return index ;
} void Node::out(){
for(int i = ;i <= ;i++){
for(int j = ;j <= ;j++)
putchar(mat[i][j]) ;
puts("") ;
}
} int father[] ;
class App{
private :
bool visited[] ;
Node start ;
char opet[] ;
public :
App(){}
App(class Node) ;
int cango(int ,int) ;
int A_star() ;
void out() ;
}; App::App(class Node s){
start = s ;
start.h = ;
start.g = start.G() ;
start.f = start.g + start.h ;
start.id = start.Hash() ;
memset(visited,,sizeof(visited)) ;
visited[start.id] = ;
} int App::cango(int x ,int y){
return <=x&&x<=&&<=y&&y<= ;
} int App::A_star(){
if(start.id == )
return ;
if(!start.cango())
return ;
priority_queue<Node>que ;
que.push(start) ;
while(!que.empty()){
Node now =que.top() ;
que.pop() ;
if(now.id == )
return ;
for(int i = ;i < ;i++){
int x = now.x + d[i][] ;
int y = now.y + d[i][] ;
if(!cango(x,y))
continue ;
Node next = now ;
next.x = x ;
next.y = y ;
swap(next.mat[now.x][now.y],next.mat[next.x][next.y]) ;
next.id = next.Hash() ;
if(visited[next.id])
continue ;
visited[next.id] = ;
if(!next.cango())
continue ;
next.g = next.G() ;
next.h = now.h + ;
next.f = next.g + next.h ;
father[next.id] = now.id ;
opet[next.id] = direction[i] ;
que.push(next) ;
}
}
return ;
} void App::out(){
if(A_star()==)
puts("unsolvable") ;
else{
vector<char>ans ;
ans.clear() ;
int i = ;
while(start.id != i){
ans.push_back(opet[i]) ;
i = father[i] ;
}
for(int i = ans.size()- ;i >= ;i--)
putchar(ans[i]) ;
puts("") ;
}
} int main(){
char str[] ;
vector<char> s ;
while(gets(str)){
s.clear() ;
for(int i = ;i < strlen(str) ;i++){
if(str[i] != ' ')
s.push_back(str[i]) ;
}
Node start ;
start = Node(s) ;
App app = App(start) ;
app.out() ;
}
return ;
}

相关知识点:

A*算法

公式表示为: f(n)=g(n)+h(n),

其中 f(n) 是从初始点经由节点n到目标点的估价函数,
g(n) 是在状态空间中从初始节点到n节点的实际代价,
h(n) 是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。
如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。

康托展开

 

{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个 123 132 213 231 312 321

代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。他们间的对应关系可由康托展开来找到。 如我想知道321是{1,2,3}中第几个大的数可以这样考虑 第一位是3,当第一位的数小于3时,那排列数小于321 如 123 213 小于3的数有1,2 所以有2*2!个 再看小于第二位2的 小于2的数只有一个就是1 所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个所以321是第6个大的数。 2*2!+1*1!是康托展开 再举个例子 1324是{1,2,3,4}排列数中第几个大的数 第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1,2但1已经在第一位了所以只有一个数2 1*2! 第三位是2小于2的数是1,但1在第一位所以有0个数 0*1! 所以比1324小的排列有0*3!+1*2!+0*1!=2个 1324是第三个大数。

HDU 1043 八数码 Eight A*算法的更多相关文章

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

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

  2. HDU 1043 八数码(A*搜索)

    在学习八数码A*搜索问题的时候须要知道下面几个点: Hash:利用康托展开进行hash 康托展开主要就是依据一个序列求这个序列是第几大的序列. A*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...

  3. HDU 1043 八数码(八境界)

    看了这篇博客的讲解,挺不错的.http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 判断无解的情况(写完七种境界才发现有直接判 ...

  4. HDU 1043 八数码问题的多种解法

    一.思路很简单,搜索.对于每一种状态,利用康托展开编码成一个整数.于是,状态就可以记忆了. 二.在搜索之前,可以先做个优化,对于逆序数为奇数的序列,一定无解. 三.搜索方法有很多. 1.最普通的:深搜 ...

  5. Eight hdu 1043 八数码问题 双搜

    Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  6. hdu 1043 八数码问题

    Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  7. HDU 1043 Eight 八数码问题 A*算法(经典问题)

    HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...

  8. HUD 1043 Eight 八数码问题 A*算法 1667 The Rotation Game IDA*算法

    先是这周是搜索的题,网站:http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6041 主要内容是BFS,A*,IDA*,还有一道K短路的,.. ...

  9. 八数码(IDA*算法)

    八数码 IDA*就是迭代加深和A*估价的结合 在迭代加深的过程中,用估计函数剪枝优化 并以比较优秀的顺序进行扩展,保证最早搜到最优解 需要空间比较小,有时跑得比A*还要快 #include<io ...

随机推荐

  1. Hive(一):架构及知识体系

    Hive是一个基于Hadoop的数据仓库,最初由Facebook提供,使用HQL作为查询接口.HDFS作为存储底层.mapReduce作为执行层,设计目的是让SQL技能良好,但Java技能较弱的分析师 ...

  2. Hibernate 抓取策略fetch-1 (select join subselect)

    原文 :http://4045060.blog.51cto.com/4035060/1088025 部分参考:http://www.cnblogs.com/rongxh7/archive/2010/0 ...

  3. 开始学习IOS

    最好的学习方式就是动手. 对于有编程经验的程序员来说,学习另外一门技术最好的方式就是coding,虽然基础知识和IDE都不熟悉,但是在写代码的过程中,不断的解决问题,不断查找资料,不断感悟代码,一切都 ...

  4. IOS开发小项目—找色块游戏

    1.项目代码: @interface NextViewController () { int r ;//色块层数的全局变量 int m;//后面用于tag值的变化 UIView *view;//色块 ...

  5. 【shell】变量的配置文件

    (1)/etc/profile   登录时,会执行.全局(公有)配置,不管是哪个用户,登录时都会读取该文件.(2)/ect/bashrc   Ubuntu没有此文件,与之对应的是/ect/bash.b ...

  6. mvc checked=\"checked\"

    <input id="IsDiscount" type="checkbox" @(Model != null && Model.IsDis ...

  7. [转]phonegap 2.9 IOS Xcode 搭建环境

    phonegap 2.9 IOS Xcode 搭建环境   一:下载phoneGap2.9和安装Xcode5(目前最新版) 选择2.9是因为3.0以上坑爹版本编译神马的要在有网络情况. 二: 下载ph ...

  8. gcc链接参数--whole-archive的作用

    // a.h extern void foo(); // a.cpp #include <stdio.h> void foo() { printf("foo\n"); ...

  9. JavaScript-获得当前时间

    js获得当前时间 var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位, ...

  10. 黄聪:百度知道中对HTML字符实体、字符编号,&开头字符的使用

    http://www.w3school.com.cn/tags/html_ref_entities.html 带有实体名称的 ASCII 实体 结果 描述 实体名称 实体编号 " quota ...