搜索训练1 [8数码问题]
来源:互联网 发布:网络平台推广 编辑:程序博客网 时间:2024/06/07 12:37
HDU1043、以及POJ1077上面都有这道题目,可以说是搜索里的非常经典的题目了。
poj上面的数据真的是弱,由于只有一组数据,简单bfs直接就可以过掉。
前前后后捣鼓了能有6个小时,才把这道题目在HDU上以4500ms的微弱优势通过。。。。。。。
我的思路一开始是简单的bfs,在HDU上超时。然后改用A*搜索,尝试了3种启发函数,才微弱的过掉。。。。我看别人的代码也是A*算法,而且启发函数写的跟我一样,为什么就几百ms过掉了呢。。。。还是不明白。。。。
思路:
(1)本题比较关键的一点就是判重问题,怎么样保证同一个状态只能被访问一次,涉及到状态的表示问题。
而状态其实是一个排列数,我们现在想要把一个排列数Hash到一个整数上,这就用到了康托展开的方法。(见我前一个博文)
(2)第二个比较关键的地方就是启发函数的选取
启发函数设置了两个参数:
val:当前状态到目标状态的哈密顿距离。
step: 当前已经移动的次数。
函数1:val + step :在poj上以67ms通过,在HDU上TLE
函数2:step为第一关键字,val为第二关键字 在poj上以760ms通过,在HDU当然TLE
函数3:以val为第一关键字,以step为第二关键字,在poj上以0ms通过,在HDU上以4500ms通过
这里还有一个需要注意的地方,就是无解情况的判定:
有一个定理,当两个状态的逆序数的奇偶性相同的时候,他们可以互相到达。
否则,他们无法互相到达,这个定理可以快速完成无解判定。
#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;class cantor{public:int fac_dp[11];int fac(int i){if(fac_dp[i]) return fac_dp[i];return fac_dp[i] = i*fac(i-1);}void init(){memset(fac_dp,0,sizeof(fac_dp));fac_dp[0] = 1;fac(10);}int encode(int num[],int n){int ans = 0;for(int i = 0;i < n;i++){int cnt = 0;for(int j = i;j < n;j++){if(num[i] > num[j])cnt++;}ans += fac_dp[n-i-1] * cnt;}return ans;}void decode(int ans[],int num,int n){int used[11];for(int i = 0;i < n;i++) used[i] = 0;for(int i = 0;i < n;i++){int cnt = num/fac_dp[n-i-1];int r = num%fac_dp[n-i-1];for(int j = 0;j < n;j++){if(!cnt && !used[j]){used[j] = 1;ans[i] = j;break;}if(!used[j]){cnt--;}}num = r;}}};struct node{int key;int val;int step;int loc;int x[9];friend bool operator<(node n1,node n2){if(n1.val == n2.val){return n1.step > n2.step;}return n1.val > n2.val;}node(int a,int b,int c,int loc):key(a),val(b),step(c),loc(loc){}};int a[11],b[11];const int MAX = 3628800;int pre[MAX];int preid[MAX];int visited[MAX];int dx[4] = {1,-1,0,0};int dy[4] = {0,0,-1,1};int tarmp[9] = {8,0,1,2,3,4,5,6,7};char dc[4] = {'d','u','l','r'};cantor ct;void prtpath(int end,int beg){char stk[100];int cnt = 0;while(end != beg){stk[cnt++] = dc[pre[end]]; end = preid[end];}while(cnt){putchar(stk[--cnt]);}puts("");}bool check(int arr[]){int sum = 0;for(int i = 0;i < 9;i++){if(arr[i] == 0) continue;for(int j = i;j < 9;j++){if(arr[j] == 0) continue;if(arr[i] > arr[j]) sum++;}}return sum%2 == 0;}int calc(int arr[]){int ans = 0;for(int i = 0;i < 9;i++){ans += abs(i/3 - tarmp[arr[i]]/3) + abs(i%3 - (tarmp[arr[i]]%3));}return ans;}int main(){ct.init();char c;while(~scanf(" %c",&c)){memset(visited,0,sizeof(visited));memset(pre,0,sizeof(pre));if(c == 'x') a[0] = 0;else a[0] = c - '0';for(int i = 1;i < 9;i++){scanf(" %c",&c);if(c == 'x'){a[i] = 0;}else{a[i] = c - '0';}}if(!check(a)){puts("unsolvable");continue;}for(int i = 0;i < 8;i++) b[i] = i+1;b[8] = 0;int tar = ct.encode(b,9);int code = ct.encode(a,9);preid[code] = code;priority_queue<node> Q; int lc = -1;while(a[++lc] != 0);node cur = node(code,calc(a),0,lc);for(int i = 0;i < 9;i++) cur.x[i] = a[i];Q.push(cur);visited[code] = 1;int f = 0;while(!Q.empty()){node nn = Q.top();Q.pop();int ccd = nn.key;if(ccd == tar){//找到了! //cout<<"YES"<<endl;prtpath(tar,code);f = 1;break;}int lc = nn.loc;int x = lc / 3;int y = lc % 3;nn.step ++;for(int i = 0;i < 4;i++){int nx = dx[i] + x;int ny = dy[i] + y;if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){int nlc = nx * 3 + ny;swap(nn.x[lc],nn.x[nlc]);int ncd = ct.encode(nn.x,9);if(!visited[ncd]){pre[ncd] = i;preid[ncd] = ccd;nn.key = ncd;nn.val = calc(nn.x);nn.loc = nlc;Q.push(nn);visited[ncd] = 1;}swap(nn.x[lc],nn.x[nlc]);}}}if(!f){puts("unsolvable");}}}
阅读全文
0 0
- 搜索训练1 [8数码问题]
- CDOJ 训练搜索专题G 八数码固定终点问题
- 启发式搜索解决8数码问题
- 八数码问题: 八数码的游戏 九宫格里面放入8个数字 启发式搜索(1)
- 八数码问题(启发式搜索)
- 【启发式搜索】八数码问题
- A*搜索 - 八数码问题
- Vijos1360[八数码问题] 搜索
- 广度优先搜索——经典的8数码问题
- 8数码问题-搜索-双向BFS/A*算法
- 八数码问题——A*搜索
- 启发式搜索程序设计-八数码问题
- Poj1077/HDU1043(A*搜索)八数码问题
- HDU 1043 八数码问题 A*搜索
- 八数码问题 经典搜索 bfs
- 搜索的分类及八数码问题
- Poj 1077 Eight 八数码问题 (搜索)
- POJ 1077 八数码问题 练习搜索
- 小象学院_Python数据分析_第二讲_数据采集与操作
- java synchronized
- java 自定义注解
- Java中几种列表的简单介绍
- Spark-大数据处理框架的安装
- 搜索训练1 [8数码问题]
- webpack学习笔记-2-file-loader 和 url-loader
- tomcat内存设置
- 错误 2 error C2491:xx: 不允许 dllimport 静态数据成员 的定义
- nvarchar和varchar的不同
- linux命令学习--sort排序命令
- Spring Security(14)——权限鉴定基础
- DCMTK学习之JPG格式与BMP格式
- 技术分析 | 新型勒索病毒Petya如何对你的文件进行加密