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 ...
随机推荐
- innodb数据库批量转换表引擎为MyISAM
2013.0106 innodb数据库批量转换表引擎为MyISAM 来源:本站原创 PHP, 数据库, 系统技术 超过488名童鞋围观 1条评论 <?php //连接数据库 $host='lo ...
- [转] matlab saveas 和imwrite的区别
http://hi.baidu.com/curbzz/item/04a69e805fc334e3e596e035 saveas(handle,['目录','文件名']) 如果只有一幅图,handle设 ...
- hyper-v 中 安装 Centos 7.0 设置网络 教程
安装环境是: 系统:win server 2012 r2 DataCenter hyper-v版本:6.3.9600.16384 centos版本:7.0 从网上下载的 centos 7.0 如果找 ...
- 在Linux中使用VS Code编译调试C++项目
最近项目需求,需要在Linux下开发C++相关项目,经过一番摸索,简单总结了一下如何通过VS Code进行编译调试的一些注意事项. 关于VS Code在Linux下的安装这里就不提了,不管是CentO ...
- 黄聪:wordpress后台导致fonts.googleapis.com、ajax.googleapis.com加载慢的解决方法
方法1.使用我做的插件.[googleapis-to-useso] 方法2.在functions.php文件里面添加下面的代码就行了. if(is_admin()) { function hcsem_ ...
- Apache HttpClient
HpptClient特性 1. 基于标准.纯净的java语言.实现了Http1.0和Http1.1 2. 以可扩展的面向对象的结构实现了Http全部的方法(GET, POST, PUT, DELETE ...
- win764上vs2010+opencv2.4.11安装配置
1:准备工作 1)opencv的官网下载你所要版本的opencv库文件,运行安装解压到自定义的一个文件夹里(D:\Program Files). 2)安装vs2010. 二:配置 1.计算机环境变量: ...
- 基于jquery的表单校验插件 - formvalidator使用体验
下载地址:http://www.formvalidator.net/ 基本样例 <form action="/registration" method="POST& ...
- 【java】简单的事件总线EventBus
public class EventBus { private static Map<String, EventListener> eventListeners = new HashMap ...
- 金蝶BOS
1, 金蝶BOS 金蝶BOS是一个开放的集成与应用平台,是金蝶企业管理软件解决方案.合作伙伴解决方案以及客户定制应用的技术平台.能够为企业灵活而迅速的设计.构建.实施和执行一套随需应变的企业管理软件系 ...