A* \IDA* 分析总结
来源:互联网 发布:xp 数据执行保护 编辑:程序博客网 时间:2024/06/06 17:10
经典八皇后问题:
#include <iostream>#include <algorithm>#include <queue>#include <vector>#include <cstdio>#include <cstring>using namespace std;struct node{ int tab[3][3]; int r,c; int hash_val; //当前排列在全排列时候的大小位置 node* pre; int op; int f,g; //f:估计值 g:从起始点到当前点的花费 bool operator < (const node& rhs)const{ return f > rhs.f; }}st,ed;node t[370000];int tot;int hash_tab[370000];priority_queue<node> open;int fn[10];int ed_map[10][2];int dir_i[4] = {0,0,1,-1};int dir_j[4] = {1,-1,0,0};char print_op[4] = {'r','l','d','u'};//处理输入的字符void In(char s[],node& t){ char ch; int next = 0; for(int i = 0;i < 3;++i){ for(int j = 0;j < 3;++j){ while(s[next] == ' ') ++next; ch = s[next++]; if(isdigit(ch)) st.tab[i][j] = ch - '0'; else { // x 的位置 st.r = i; st.c = j; st.tab[i][j] = 0; } } }}//获取估价函数值int get_f(node a,int g){ int h = 0; for(int i = 0;i < 3;++i) for(int j = 0;j < 3;++j) if(a.tab[i][j]) //距离目标点的曼哈顿距离 h += abs(i - ed_map[a.tab[i][j]][0]) + abs(j - ed_map[a.tab[i][j]][1]); return g + h;}//康拓展开,判断该组合在所有排列中的位置int get_hash(node a){ int ret; ret = 0; int num = 8; for(int i = 0;i < 3;++i){ for(int j = 0;j < 3;++j){ int x = 0; //当前这个数后有多少个比他小 for(int jj = j + 1;jj < 3;++jj) if(a.tab[i][jj] < a.tab[i][j]) x++; for(int ii = i + 1;ii < 3;++ii) for(int jj = 0;jj < 3;++jj) if(a.tab[ii][jj] < a.tab[i][j]) x++; ret += fn[num] * x; //康拓展开 num--; } } return ret;}//预处理void init(){ memset(hash_tab,0,sizeof(hash_tab)); while(!open.empty()) open.pop(); tot = 0; st.f = get_f(st,0); //获取估价函数值 st.g = 0; st.hash_val = get_hash(st); //获取该组合在全排列的位置 open.push(st); hash_tab[st.hash_val] = 1; //当前的组合排列已经遍历过了}void pre(){ //预处理阶乘 fn[0] = 1; for(int i = 1;i < 9;++i) fn[i] = i * fn[i - 1]; //预处理结果 for(int i = 0;i < 3;++i) for(int j = 0;j < 3;++j) ed.tab[i][j] = (i * 3) + j + 1; ed.tab[2][2] = 0; ed.hash_val = get_hash(ed); //预处理结果位置的映射 for(int i = 0;i < 3;++i) for(int j = 0;j < 3;++j) if(ed.tab[i][j]){ ed_map[ed.tab[i][j]][0] = i; ed_map[ed.tab[i][j]][1] = j; }}//判断逆序数的奇偶性int get_preval(node a){ int ret = 0; for(int i = 0;i < 3;++i) for(int j = 0;j < 3;++j){ if(!a.tab[i][j]) continue; int x = 0; for(int jj = j + 1;jj < 3;++jj) if(a.tab[i][jj] && a.tab[i][jj] < a.tab[i][j]) x++; for(int ii = i + 1;ii < 3;++ii) for(int jj = 0;jj < 3;++jj) if(a.tab[ii][jj] && a.tab[ii][jj] < a.tab[i][j]) x++; ret += x; } return ret & 1;}bool pre_solve(){ return(get_preval(st)^(get_preval(ed)));}void change(node &tmp,node a,int nextr,int nextc,int _i,int idx){ for(int i = 0;i < 3;++i) for(int j = 0;j < 3;++j) tmp.tab[i][j] = a.tab[i][j]; swap(tmp.tab[nextr][nextc],tmp.tab[a.r][a.c]); tmp.hash_val = get_hash(tmp); tmp.r = nextr; tmp.c = nextc; tmp.pre = &t[idx]; tmp.op = _i; //移动的方向 tmp.g = a.g + 1; //当前的步数 tmp.f = get_f(tmp,tmp.g);}bool check(int i,int j){ if(i > 2 || i < 0 || j > 2 || j < 0) return false; return true;}//打印路径void path(node* a){ if(a->hash_val == st.hash_val) return ; path(a->pre); printf("%c",print_op[a->op]);}//A*void Astar(){ int nextr,nextc; node ans = st; int fla = 0; if(st.hash_val != ed.hash_val) while(!open.empty()){ node a = open.top(); open.pop(); t[++tot] = a; for(int i = 0;i < 4;++i){ nextr = a.r + dir_i[i]; nextc = a.c + dir_j[i]; if(check(nextr,nextc)){ node tmp; change(tmp,a,nextr,nextc,i,tot); if(hash_tab[tmp.hash_val]) continue; if(tmp.hash_val == ed.hash_val){ fla = 1; ans = tmp; break; } open.push(tmp); } } if(fla) break; hash_tab[a.hash_val] = 1; } path(&ans); puts("");}int main(){ // freopen("Input.txt","r",stdin); char ss[12]; while(gets(ss)){ pre(); In(ss,st); init(); if(pre_solve()) puts("unsolvable"); else Astar(); } return 0;}
对于空格(0)的左移/右移操作,对应序列不变(逆序数也就不变)
对于空格(0)的上移/下移操作,相当于序列的某个数字前移/后移两位,该序列的逆序数奇偶性不变。
所以求初始状态与目标状态的逆序数可作出判断
例中前者为奇,后者为偶,因此无解
利用奇偶性判断所给出的初始状态有无解.
判别方法是:
以数组为一维的举例子.
将八数码的一个结点表示成一个数组a[9],空格用0表示,设临时函数p(x)定义为:x数所在位置前面的数比x小的数的个数,
其中0空格不算在之内,那设目标状态为b[9],那r=sigma(p(x)) sigma()表示取所有的x:1-8并求和,
那对于初始状态a[9],t=sigma(p(x)),如果r和t同为奇数或者同为偶数,那么该状态有解,否则无解。
考虑到四种移动方法对sigma(p(x))的影响,左移和右移是不会影响它的值的,
更不会影响奇偶性,如果是上移或者下移就会影响:
上移:一次上移会使一个元素向前跳两个数字的位置,设这两个数字为a1,a2,
不妨设a1<a2,移的这个数字设为a0,那无非只有以下三次情况:
1,a0<a1<a2,考虑它们三者的p(x)值,p(a0)不变,p(a1)++,p(a2)++,总体增加了2
2,a1<a0<a2,p(a0)--,p(a1)不变,p(a2)++,总体不变
3,a1<a2<a0,p(a0)-=2,p(a1),p(a2)不变,总体减小了2
综合起来的结论就是不会影响sigma(p(x))的奇偶性。
1 0
- A* \IDA* 分析总结
- A* IDA*
- 菜鸟总结so分析,arm 汇编,IDA静态分析
- poj1077(A*,IDA*)
- A*,IDA*,Dijkstra
- 搜索,A* IDA*
- A*和IDA*算法
- 迭代深搜+A*(IDA*)
- IDA 分析BIOS
- 用IDA分析so
- IDA*算法总结
- ida 使用 问题总结
- 【以后再做再总结】【IDA*】【Jason's_ACM_解题报告】Editing a Book
- (A*,IDA*,DFS)eight(p1077)
- A*算法 和 IDA*算法
- 【IDA*搜索】uva11212Editing a Book
- A*算法 与 IDA*算法
- IDA*对A*的改进
- 网络协议的三次握手
- 内螺旋和外螺旋自然序列的实现
- C++中的new、operator new与placement new
- 树状数组应用之——求逆序对
- Django 1.7 初级教程or学习笔记(三)
- A* \IDA* 分析总结
- 在线学习网站整理
- TCP的Socket技术之服务器端
- 【coursera 学习笔记】An Introduction to Interactive Programming in Python--week0
- 树状数组应用之——区间修改 点查询
- hdu3449 有依赖的背包问题
- Reverse word in a string [leetcode]
- java基础之IO流中的PipedStream管道流和RandomAcessFile
- java的反射机制