HDU 1043 八数码 Eight A*算法
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
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.
1 2 3
x 4 6
7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
#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),
康托展开
{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*算法的更多相关文章
- Eight POJ - 1077 HDU - 1043 八数码
Eight POJ - 1077 HDU - 1043 八数码问题.用hash(康托展开)判重 bfs(TLE) #include<cstdio> #include<iostream ...
- HDU 1043 八数码(A*搜索)
在学习八数码A*搜索问题的时候须要知道下面几个点: Hash:利用康托展开进行hash 康托展开主要就是依据一个序列求这个序列是第几大的序列. A*搜索:这里的启示函数就用两点之间的曼哈顿距离进行计算 ...
- HDU 1043 八数码(八境界)
看了这篇博客的讲解,挺不错的.http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 判断无解的情况(写完七种境界才发现有直接判 ...
- HDU 1043 八数码问题的多种解法
一.思路很简单,搜索.对于每一种状态,利用康托展开编码成一个整数.于是,状态就可以记忆了. 二.在搜索之前,可以先做个优化,对于逆序数为奇数的序列,一定无解. 三.搜索方法有很多. 1.最普通的:深搜 ...
- Eight hdu 1043 八数码问题 双搜
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- hdu 1043 八数码问题
Eight Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- HDU 1043 Eight 八数码问题 A*算法(经典问题)
HDU 1043 Eight 八数码问题(经典问题) 题意 经典问题,就不再进行解释了. 这里主要是给你一个状态,然后要你求其到达\(1,2,3,4,5,6,7,8,x\)的转移路径. 解题思路 这里 ...
- HUD 1043 Eight 八数码问题 A*算法 1667 The Rotation Game IDA*算法
先是这周是搜索的题,网站:http://acm.hdu.edu.cn/webcontest/contest_show.php?cid=6041 主要内容是BFS,A*,IDA*,还有一道K短路的,.. ...
- 八数码(IDA*算法)
八数码 IDA*就是迭代加深和A*估价的结合 在迭代加深的过程中,用估计函数剪枝优化 并以比较优秀的顺序进行扩展,保证最早搜到最优解 需要空间比较小,有时跑得比A*还要快 #include<io ...
随机推荐
- jquery组件团购倒计时功能
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Spring boot配合Spring session(redis)遇到的错误
背景:本MUEAS项目,一开始的时候,是没有引入redis的,考虑到后期性能的问题而引入.之前没有引用redis的时候,用户登录是正常的.但是,在加入redis支持后,登录就出错!错误如下: . __ ...
- Asp.Net MVC 路由 - Asp.Net 编程 - 张子阳
http://cache.baiducontent.com/c?m=9d78d513d98316fa03acd2294d01d6165909c7256b96c4523f8a9c12d522195646 ...
- 【linux】grub详解
参数解释 1. default=0 # default后加一个数字n,表示n+1个“title”操作系统,0表示第一个“title” 的操作系统,以此类推. 2. timeout=0 # timeou ...
- 【转】JVM 分代GC策略分析
我们以Sun HotSpot VM来进行分析,首先应该知道,如果我们没有指定任何GC策略的时候,JVM默认使用的GC策略.Java虚拟机是按照分代的方式来回收垃圾空间,我们应该知道,垃圾回收主要是针对 ...
- bzoj4109: [Wf2015]Cutting Cheese
Description 给定一个100*100*100(单位:毫米)的奶酪方块,这个奶酪含有n个球形小孔.现在要求将这个奶酪切成s片使得每片质量相等. Input 第一行包含两个整数n,s,表示奶酪有 ...
- TCP中需要了解的东西
1.TCP是一个流协议. TCP跟UDP不一样的是,TCP发送过去的东西是stream,也就是说第一次发送的跟第二次发送的数据包可能会粘在一起,即所谓的粘包问题 http://blog.csdn.ne ...
- HDU2490 parade
题目大意:一个n+1行m+1列的表格,每个格子两个数w和c,表示经过该格子的happy和体力消耗值tireness.现在从最下面任意处开始,可以向左向右向上走.但不能向下.每个格子不能经过两次.在每一 ...
- C语言每日一题之No.1
鉴于在学校弱弱的接触过C,基本上很少编程,C语言基础太薄弱.刚好目前从事的是软件编程,难度可想而知.严重影响工作效率,已无法再拖下去了.为此,痛下决心恶补C语言.此前只停留在看书,光看好像也记不住,C ...
- 静态库不要strip 太厉害
根据strip的功能表示,strip经常用来去除目标文件中的一些符号表.调试符号表信息,减少包的大小.我自己做了一函数库,同样的代码生成了一个mylib.so和一个mylib.a文件,之后使用了 st ...