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. jquery组件团购倒计时功能

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. Spring boot配合Spring session(redis)遇到的错误

    背景:本MUEAS项目,一开始的时候,是没有引入redis的,考虑到后期性能的问题而引入.之前没有引用redis的时候,用户登录是正常的.但是,在加入redis支持后,登录就出错!错误如下: . __ ...

  3. Asp.Net MVC 路由 - Asp.Net 编程 - 张子阳

    http://cache.baiducontent.com/c?m=9d78d513d98316fa03acd2294d01d6165909c7256b96c4523f8a9c12d522195646 ...

  4. 【linux】grub详解

    参数解释 1. default=0 # default后加一个数字n,表示n+1个“title”操作系统,0表示第一个“title” 的操作系统,以此类推. 2. timeout=0 # timeou ...

  5. 【转】JVM 分代GC策略分析

    我们以Sun HotSpot VM来进行分析,首先应该知道,如果我们没有指定任何GC策略的时候,JVM默认使用的GC策略.Java虚拟机是按照分代的方式来回收垃圾空间,我们应该知道,垃圾回收主要是针对 ...

  6. bzoj4109: [Wf2015]Cutting Cheese

    Description 给定一个100*100*100(单位:毫米)的奶酪方块,这个奶酪含有n个球形小孔.现在要求将这个奶酪切成s片使得每片质量相等. Input 第一行包含两个整数n,s,表示奶酪有 ...

  7. TCP中需要了解的东西

    1.TCP是一个流协议. TCP跟UDP不一样的是,TCP发送过去的东西是stream,也就是说第一次发送的跟第二次发送的数据包可能会粘在一起,即所谓的粘包问题 http://blog.csdn.ne ...

  8. HDU2490 parade

    题目大意:一个n+1行m+1列的表格,每个格子两个数w和c,表示经过该格子的happy和体力消耗值tireness.现在从最下面任意处开始,可以向左向右向上走.但不能向下.每个格子不能经过两次.在每一 ...

  9. C语言每日一题之No.1

    鉴于在学校弱弱的接触过C,基本上很少编程,C语言基础太薄弱.刚好目前从事的是软件编程,难度可想而知.严重影响工作效率,已无法再拖下去了.为此,痛下决心恶补C语言.此前只停留在看书,光看好像也记不住,C ...

  10. 静态库不要strip 太厉害

    根据strip的功能表示,strip经常用来去除目标文件中的一些符号表.调试符号表信息,减少包的大小.我自己做了一函数库,同样的代码生成了一个mylib.so和一个mylib.a文件,之后使用了 st ...