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. git在本地创建远程仓库

    类似的博文,在前面的帖子里面也提到过,当时讲述的是一个入门级别的.其URL是ssh://username@repo-host-address/repo-path这种格式. 今天再说说如何创建类似Git ...

  2. Angular学习(1)

    天天都是hello world,老子玩1+1. 最简单的例子,见证无聊的时刻: <!DOCTYPE html> <html> <head> <title> ...

  3. Servlet Filter 3

    11.MD5加密 /** * 使用md5的算法进行加密 */ public static String md5(String plainText) { byte[] secretBytes = nul ...

  4. 清理java环境

    system32中存在3个java*.exe文件,分别是: c:/windows/system32/java.exe c:/windows/system32/javaw.exe c:/windows/ ...

  5. Linux下nl命令的用法详解

    Linux中nl命令和cat命令很像,不过nl命令会打上行号,属于比较不常用的命令,下面随小编一起来了解下这个鲜为人知的nl命令吧. nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文 ...

  6. source insight 里编辑的时候,每次粘贴后,光标停留在粘贴内容的左面

    在source insight 里编辑的时候,每次粘贴后,光标停留在粘贴内容的左面.我想把它设定为 粘贴后,光标移动倒粘贴内容的右面. 该怎么做? 这是个设置问题,按照下面的步骤设定就可以了. Opt ...

  7. 128. Longest Consecutive Sequence

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ...

  8. c# 存档修改 读取 写入

    内涵图

  9. SOA_环境安装系列4_Oracle SOA安装和环境搭建(案例)

    2015-01-02 Created By BaoXinjian

  10. CF 500 B. New Year Permutation 并查集

    User ainta has a permutation p1, p2, ..., pn. As the New Year is coming, he wants to make his permut ...