[HDU 1043] Eight A*或IDA*
来源:互联网 发布:淘宝客qq群如何拉人 编辑:程序博客网 时间:2024/05/22 17:11
http://acm.hdu.edu.cn/showproblem.php?pid=1043
题意:将八数码变成1 2 3 4 5 6 7 8 x
思路:就是普通的A*,IDA*, 用一个数组保存路径,vis数组保存移动方向, 还有开始要判断其实状态的逆序数和目标状态的逆序数是否一样。
求解八数码的时候IDA* 确实比 A* 要快,代码也短一点,可悲的是,这两个代码竟然都比一年前写的慢,难道我还退步了啊,算了 也懒得优化了。
IDA*代码(655ms):
#include <queue>#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int maxn = 400000;const char prt[4] = {'r', 'd', 'u', 'l'}; //方向输出const int Move[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; //移动方向const int fsh[10][2] = {{2, 2}, {0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}; //目标状态每个数的坐标,用于计算曼哈顿距离char sta[105]; //保存路径int abs(int a){ return a < 0 ? -a : a;}int Manhattan(int *num) //曼哈顿距离{ int sum = 0; for(int i = 0; i < 9; i++){ sum += abs(fsh[num[i]][0] - i/3) + abs(fsh[num[i]][1] - i%3); } return sum;}int isok(int *mapn) //求逆序数{ int sum=0; for(int i = 0; i < 9; i++) { int num = 0; if(mapn[i] == 0) continue; for(int k = i+1; k < 9; k++) { if(mapn[i] > mapn[k] && mapn[k]) { num++; } } sum += num; } return sum;}bool IdaStar(int *mapn, int x, int y, int pre, int step, int upper) //IDA*搜索{ int nx, ny; //四个方向 for(int i = 0; i < 4; i++){ nx = x + Move[i][0]; ny = y + Move[i][1]; if(pre + i == 3 || nx < 0 || nx > 2 || ny < 0 || ny > 2) //回到前驱或者出界 continue; mapn[3 * x + y] = mapn[3 * nx + ny]; //交换 mapn[3 * nx + ny] = 0; int mht = Manhattan(mapn); //计算曼哈顿距离(估价函数,相当于最少还要多少步) if(mht == 0){ //到达终点 sta[step] = prt[i]; sta[step+1] = '\0'; return true; } if(mht + step <= upper){ //剪枝 sta[step] = prt[i]; if(IdaStar(mapn, nx, ny, i, step+1, upper)) return true; } mapn[3 * nx + ny] = mapn[3 * x + y]; //交换回来 mapn[3 * x + y] = 0; } return false;}int main(){ char str[10]; while(cin>>str[0]){ for(int i = 1; i < 9; i++){ cin>>str[i]; } int mapn[10], x, y; for(int i = 0; i < 9; i++){ if(str[i] == 'x'){ x = i / 3; y = i % 3; mapn[i] = 0; } else mapn[i] = str[i] - '0'; } if(isok(mapn) % 2 == 1) cout<<"unsolvable"<<endl; else{ int ans = Manhattan(mapn); if(ans == 0){ cout<<endl; } else{ int top = 0; while(++top){ //top表示搜索的上限 if(IdaStar(mapn, x, y, -1, 0, top)) //搜索成功 break; } cout<<sta<<endl; } } } return 0;}
A*代码(1513ms):
#include <queue>#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int maxn = 400000;const char prt[4] = {'r', 'l', 'd', 'u'}; //方向const int Move[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; //移动const int dis[12] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800}; //计算康拓值的数组const int fsh[10][2] = {{2, 2}, {0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}; //目标状态每个数的坐标,用于计算曼哈顿距离struct node{ int key; //用康拓值保存图 int x, y; // 0 的位置 int step, mht; //step表示走了多少步,mht 表示最少还要多少步 friend bool operator < (node a, node b){ //优先队列,b.step+b.mht 小的先出队 return a.step+a.mht > b.step+b.mht; }};int pre[maxn]; //保存前驱int vis[maxn]; //用于判重,顺便保存移动方向priority_queue<node> que; //优先队列inline int abs(int a){ return a > 0 ? a : -a;}int Cantor(int *arg, int len) //康拓展开{ int resl = 1; for(int i = 0; i < len; i++){ int counts = 0; for(int k = i + 1; k < len; k++){ if(arg[i] > arg[k]){ counts++; } } resl = resl + dis[len-i-1] * counts; } return resl;}void InvCantor(int *arg, int num, int len) // 逆康拓{ num = num - 1; bool vis[12] = {false}; for(int i = 0; i < len; i++){ int mid = 0; int cnt = num / dis[len-i-1]; while(++mid){ if(!vis[mid]){ if(cnt == 0) break; cnt--; } } arg[i] = mid - 1; vis[mid] = true; num = num % dis[len-i-1]; }}int Manhattan(int *num) //曼哈顿距离{ int sum = 0; for(int i = 0; i < 9; i++){ sum += abs(fsh[num[i]][0] - i/3) + abs(fsh[num[i]][1] - i%3); } return sum;}int isok(int *mapn) //求逆序数{ int sum=0; for(int i = 0; i < 9; i++) { int num = 0; if(mapn[i] == 0) continue; for(int k = i+1; k < 9; k++) { if(mapn[i] > mapn[k] && mapn[k]) { num++; } } sum += num; } return sum;}int print(int rt) //输出路径{ if(pre[rt] == -1){ return 0; } print(pre[rt]); cout<<prt[vis[rt]];}int Astar(int *mapn, int x, int y) //A*搜索{ node w, r; w.step = 0; w.x = x, w.y = y; w.mht = Manhattan(mapn); w.key = Cantor(mapn, 9); vis[w.key] = 0; while(!que.empty()) que.pop(); que.push(w); while(!que.empty()) { r = que.top(), que.pop(); InvCantor(mapn, r.key, 9); for(int i = 0; i < 4; i++){ w.x = r.x + Move[i][0]; w.y = r.y + Move[i][1]; if(w.x < 0 || w.x > 2 || w.y < 0 || w.y > 2) continue; mapn[(r.x * 3 + r.y)] = mapn[(w.x * 3 + w.y)]; //移动 0 mapn[(w.x * 3 + w.y)] = 0; w.key = Cantor(mapn, 9); //计算康拓值 w.mht = Manhattan(mapn); //计算曼哈顿距离 if(vis[w.key] == -1){ w.step = r.step + 1; que.push(w); vis[w.key] = i; pre[w.key] = r.key; if(w.mht == 0){ print(w.key); cout<<endl; return 0; } } mapn[(w.x * 3 + w.y)] = mapn[(r.x * 3 + r.y)]; 移动回来 mapn[(r.x * 3 + r.y)] = 0; } } return -1;}int main(){ char str[10]; while(cin>>str[0]){ for(int i = 1; i < 9; i++){ cin>>str[i]; } int mapn[10], x, y; for(int i = 0; i < 9; i++){ if(str[i] == 'x'){ x = i / 3; y = i % 3; mapn[i] = 0; } else mapn[i] = str[i] - '0'; } if(isok(mapn) % 2 == 1) cout<<"unsolvable"<<endl; else{ int ans = Manhattan(mapn); if(ans == 0){ cout<<endl; } memset(pre, -1, sizeof(pre)); memset(vis, -1, sizeof(vis)); Astar(mapn, x, y); } } return 0;}
0 0
- [HDU 1043] Eight A*或IDA*
- POJ 1077 HDU 1043 Eight (IDA*)
- hdu 1043 eight a*
- hdu 1043 Eight(A*)
- poj 1077 & hdu 1043 Eight ( 多种解法:预处理、bfs、dbfs、IDA*、A*)
- HDU Eight (2) A* IDA*都是浮云啊。。
- (A*,IDA*,DFS)eight(p1077)
- HDU-1043 Eight(A*)
- poj 1077 Eight (bfs A* IDA*)
- 八数码 poj1077 Eight(A*、IDA*)
- HDU-1043:Eight(八数码+bfs(反向或A*))
- hdu 1043 Eight 双向BFS/A*算法
- HDU 1043 && POJ 1077 Eight (A*)
- POJ 1077 Eight A*算法 IDA*算法 康拓展开
- POJ 1077 Eight(八数码A*+IDA*)
- POJ 1077 Eight && HDU 1043 Eight 八数码问题(A*算法)
- hdu 1043 eight 八数码问题 bfs 和 A*
- HDU 1043 Eight 八数码问题 A*搜索 启发式算法
- 学习笔记-gitHub使用
- Android Activity 组件生命周期
- poj 2431 Expedition 优先队列 大顶堆
- 数字图像处理02(直方图及均衡化,规定化,局部对比度增强)
- iOS操作小整理
- [HDU 1043] Eight A*或IDA*
- 哈弗曼编码
- TrustZone技术简介
- Ubuntu14.04配置OpenCV3.0的方法
- 引用和指针的区别
- iOS学习之旅之C语言day4
- hdu 5301 Buildings
- 自定义ProgressBar样式custom_progressbar.xml
- 数组的常用算法(1)--由“为了集齐108将买多少袋干脆面”展开去