HDU 1043 八数码问题 A*搜索+康拓展开+逆序对判断+路径输出
来源:互联网 发布:python黑帽子中文 编辑:程序博客网 时间:2024/06/05 15:28
康托展开:和其他一样,为了方便表示各个状态,让每个状态都变成一个数来表示
逆序对判断:如果图八数码,那个这个图所有的逆序对之和一定是偶数的,如果是奇数,则不是八数码
路径输出: pre数组记录前置点,vis数组同时表示是否访问过,也记录着方向。到达这个点是都得什么方向。
A*搜索:建立一个queue,按照g排序,优先访问g小的,g相同访问h小的。 而估价函数是用的曼哈顿距离
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<map>
#include<string>
#define inf 1<<30
#define eps 1e-7
#define LD long double
#define LL long long
#define maxn 1000000005
using namespace std;
struct Node{
int maze[3][3]; //八数码具体情况
int h,g; //两个估价函数
int x,y; //空位的位置
int Hash; //HASH值
bool operator<(const Node n1)const{ //优先队列第一关键字为h,第二关键字为g
return h!=n1.h?h>n1.h:g>n1.g;
}
bool check(){ //判断是否合法
if(x>=0&&x<3&&y>=0&&y<3)
return true;
return false;
}
}s,u,v,tt;
int HASH[9]={1,1,2,6,24,120,720,5040,40320}; //HASH的权值
int destination=322560; //目标情况的HASH值
int vis[400000]; //判断状态已遍历,初始为-1,否则为到达这步的转向
int pre[400000]; //路径保存
int way[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; //四个方向
void debug(Node tmp){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++)
printf("%d ",tmp.maze[i][j]);
printf("\n");
}
printf("%d %d\n%d %d\n",tmp.x,tmp.y,tmp.g,tmp.h);
printf("hash=%d\n",tmp.Hash);
}
int get_hash(Node tmp){ //获得HASH值
int a[9],k=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
a[k++]=tmp.maze[i][j];
int res=0;
for(int i=0;i<9;i++){
int k=0;
for(int j=0;j<i;j++)
if(a[j]>a[i])
k++;
res+=HASH[i]*k;
}
return res;
}
bool isok(Node tmp){ //求出逆序对,判断是否有解
int a[9],k=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
a[k++]=tmp.maze[i][j];
int sum=0;
for(int i=0;i<9;i++)
for(int j=i+1;j<9;j++)
if(a[j]&&a[i]&&a[i]>a[j])
sum++;
return !(sum&1); //由于目标解为偶数,所以状态的逆序数为偶数才可行
}
int get_h(Node tmp){ //获得估价函数H
int ans=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(tmp.maze[i][j])
ans+=abs(i-(tmp.maze[i][j]-1)/3)+abs(j-(tmp.maze[i][j]-1)%3);
return ans;
}
void astar(){ //搜索
priority_queue<Node>que;
que.push(s);
while(!que.empty()){
u=que.top();
que.pop();
for(int i=0;i<4;i++){
v=u;
v.x+=way[i][0];
v.y+=way[i][1];
if(v.check()){
swap(v.maze[v.x][v.y],v.maze[u.x][u.y]); //将空位和相邻位交换
v.Hash=get_hash(v); //得到HASH值
if(vis[v.Hash]==-1){ //判断是否已遍历且是否可行,后者可以不要
vis[v.Hash]=i; //保存方向
v.g++;; //已花代价+1
pre[v.Hash]=u.Hash; //保存路径
v.h=get_h(v); //得到新的估价函数H
que.push(v); //入队
}
if(v.Hash==destination)
return ;
}
}
}
}
void print(){
string ans;
ans.clear();
int nxt=destination;
while(pre[nxt]!=-1){ //从终点往起点找路径
switch(vis[nxt]){ //四个方向对应
case 0:ans+='r';break;
case 1:ans+='l';break;
case 2:ans+='d';break;
case 3:ans+='u';break;
}
nxt=pre[nxt];
}
for(int i=ans.size()-1;i>=0;i--)
putchar(ans[i]);
puts("");
}
int main(){
char str[100];
while(gets(str)!=NULL){
int k=0;
memset(vis,-1,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(int i=0;i<3;i++)
for(int j=0;j<3;j++){
if((str[k]<='9'&&str[k]>='0')||str[k]=='x'){
if(str[k]=='x'){
s.maze[i][j]=0;
s.x=i;
s.y=j;
}
else
s.maze[i][j]=str[k]-'0';
}
else
j--;
k++;
}
if(!isok(s)){ //起始状态不可行
printf("unsolvable\n");
continue;
}
s.Hash=get_hash(s);
if(s.Hash==destination){ //起始状态为目标状态
puts("");
continue;
}
vis[s.Hash]=-2;
s.g=0;s.h=get_h(s);
astar();
print();
}
return 0;
}
阅读全文
0 0
- HDU 1043 八数码问题 A*搜索+康拓展开+逆序对判断+路径输出
- poj 1077 hdu 1043 Eight 八数码问题 DBFS(双向广度优先搜索)a*算法 康拓展开
- HDU-1043 Eight(经典八数码问题, A*+康拓+曼哈顿距离+逆序数判断可解性、双向搜索)
- HDU 1043 八数码问题 A*搜索
- HDU 1043 八数码问题 A*搜索
- hdu 1043 八数码问题-A*搜索
- hdu 1043 Eight(八数码问题 高级搜索: A* 搜索)
- HDU 1043 Eight 八数码问题 A*搜索 启发式算法
- 八数码(A*+路径输出+逆序数+康托展开式hash)
- HDU 1043 八数码 反向BFS+康拓展开
- HDU 1043 八数码(A*搜索)
- A*搜索 - 八数码问题
- UVA 10085(bfs+康拓展开)八数码问题
- 八数码问题 poj 1077 康拓展开
- hdu 1043 八数码 A*
- 八数码问题——A*搜索
- Poj1077/HDU1043(A*搜索)八数码问题
- 八数码问题-启发式搜索(A*算法)
- ServletRequest中getReader()和getInputStream()只能调用一次的解决办法
- 二叉树的下一个节点
- LintCode 关于动态规划问题的总结
- 从K近邻算法、距离度量谈到KD树、SIFT+BBF算法
- day10笔记
- HDU 1043 八数码问题 A*搜索+康拓展开+逆序对判断+路径输出
- 隐含马尔科夫模型(HMM)原理及其实现
- spring总结
- 计算1+2+.....+n
- android 网络连接的判断
- C语言入门——奇偶个数
- 算法精解_C语言 链表_单链表(应用:页帧管理)
- 1、继承 2、抽象类 3、综合案例---员工类系列定义
- 累乘法