poj 1077 Eight (八数码问题——A*+cantor展开+奇偶剪枝)
Posted acboyty
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 1077 Eight (八数码问题——A*+cantor展开+奇偶剪枝)相关的知识,希望对你有一定的参考价值。
题目来源:
http://poj.org/problem?id=1077
题目大意:
给你一个由1到8和x组成的3*3矩阵,x每次可以上下左右四个方向交换。求一条路径,得到12345678x这样的矩阵。若没有路径,则输出unsolvable。
经典的八数码问题。
这题我用A*算法做的。推荐一篇博客,从大体上介绍了一下启发式算法的代表A*算法:
https://www.cnblogs.com/zhoug2020/p/3468167.html
说说这道题的几个注意点:
首先就是判重的问题,搜索的状态是九个数(含x),开个九重数组也不是不可以,但用cantor展开hash一下还是方便的。所谓cantor展开,就是对1..n的所有排列,唯一对应一个1..n!的值。代码中的cantor展开,可以当做模板用。
其次就是奇偶剪枝了。对于1..n的排列来说,每次对换两个元素,排列逆序数的奇偶性一定改变。而容易发现,和x交换,1..8的排列逆序数奇偶性是不变的。故可以实现判断是否是unsolvable。
最后就是Astar算法本身了:
首先需要一个优先队列。由于对优先级的需要,我们需要在结构体中对<运算符进行重载(详见代码)。
然后结构体中存储路径最好还是用string吧,毕竟vector还是没它方便。
好像就是这么多。搜索这种东西,复杂度比较难把握,所以能优化的地方尽量优化一下吧。比如搜索方向,感觉还是先搜索down和right比较好,虽然可能效果不太明显。
这道题还要继续做。hdu1043还没A掉,双向BFS,还有什么打表方法还没有尝试写呢。加上!!!,表示要记得做!
#include<iostream> #include<cstdio> #include<string> #include<queue> #include<cstring> using namespace std; char buf[30]; int puz[9]; int fac[]={1,1,2,6,24,120,720,5040,40320,362880}; int cantor(int s[]) { int sum=0; for(int i=0;i<9;i++) { int num=0; for(int j=i+1;j<9;j++) if(s[j]<s[i]) num++; sum+=(num*fac[9-i-1]); } return sum+1; } struct tnode { int puz[9]; string path; int loc;//0的位置 int status;//cantor展开值 int n;//搜索深度 int f;//估值函数 int getloc() { for(int i=0;i<9;i++) if(puz[i]==0) return i; } bool operator<(const tnode& y) const { return f>y.f; } }; int vis[363000]; int dis[9]={4,3,2,3,2,1,2,1,0}; int a[4]={1,3,-1,-3}; char b[5]="rdlu"; int aim=46234; int main() { while(scanf("%[^ ]",buf)!=EOF) { getchar(); for(int i=0,cnt=0;buf[i]!=‘