借助八数码问题,双向广搜,康托展开,逆序数奇偶性
来源:互联网 发布:破解局域网mac限制 编辑:程序博客网 时间:2024/06/13 20:19
1.首先判断是否有解
核心思想是根据一维状态的逆序数奇偶性来判断
将它表征为一维状态(0 1 2 3 4 5 6 7 8),它的逆序数为0,偶数。考虑数字的移动,左移or右移均不改变其一维状态,因此逆序数的奇偶性不变。上移or下移时,一维状态中某一位的数字往前或者往后跳了两格(+/-2),相应的,逆序数+/-2,依然不改变奇偶性。因此有结论:八数码问题有解 iff 初始状态与终止状态的逆序数奇偶性一致。
所以一个完美的八数码问题求解,必须先判断其解是否存在,再行搜索2.双向广搜理论上可以减少一半的空间,时间。
1)将始 终状态都入队列并在相当的标记中为1,2(加以区分)
2)每次新的状态的标记都与上次的相同,并判断若有一个标记走到了另一个标记,结束
3)若要输出过程,标记变化的地方要单独输出
一个很好的模版 poj1915
#include <stdio.h>#include <stdlib.h>int vis[305][305], mat[305][305];int dx[] = {-2, -2, -1, 1, 2, 2, 1, -1};int dy[] = {-1, 1, 2, 2, 1, -1, -2, -2};int casenum, nNum, sx, sy, tx, ty, i;struct point{ int x, y;}cur, next, q[90005]={0};int IsInBound(int x, int y){ return (x>=0 && y>=0 && x<nNum && y<nNum);}/* IsInBound */int Solve(){ int rear = -1; int front = -1; cur.x = sx; cur.y = sy; vis[sx][sy] = 1; /* 从起始位置开始的探索标记为 1 */ q[++rear] = cur; /* 起始坐标入队 */ next.x = tx; next.y = ty; vis[tx][ty] = 2; /* 从终点位置开始的探索标记为 2 */ q[++rear] = next; /* 终点坐标入队 */ while (front < rear) { cur = q[++front]; /* 队首节点坐标出队 */ for (i=0; i<8; ++i) { next.x = cur.x + dx[i]; next.y = cur.y + dy[i]; if (!IsInBound(next.x, next.y)) continue; if (!vis[next.x][next.y]) { vis[next.x][next.y] = vis[cur.x][cur.y]; /* 设为与当前探索路径相同的标记 */ mat[next.x][next.y] = mat[cur.x][cur.y] + 1; /* 记录步数 */ q[++rear] = next; /* 当前合法坐标位置入队 */ } else if (vis[cur.x][cur.y] != vis[next.x][next.y]) { /* 说明从起点出发的探索与从终点出发的探索重合 */ return mat[cur.x][cur.y]+mat[next.x][next.y]+1;//步数 } }/* End of For */ }/* End of While */}/* Solve */int main(){ scanf("%d", &casenum); while (casenum--) { memset(vis, 0, sizeof(vis)); memset(mat, 0, sizeof(mat)); scanf("%d", &nNum); scanf("%d %d", &sx, &sy); scanf("%d %d", &tx, &ty); if (sx==tx && sy==ty) { printf("0\n"); } else { printf("%d\n", Solve()); } }/* End of While */ return 0;}3.康托展开,hash判重
另一个完整的八数码结题答案
/*HDU 1043 Eight思路:反向搜索,从目标状态找回状态对应的路径用康托展开判重AC G++ 328ms 13924K*/#include<stdio.h>#include<string.h>#include<iostream>#include<queue>#include<string>using namespace std;const int MAXN=1000000;//最多是9!/2int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重// 0!1!2!3! 4! 5! 6! 7! 8! 9!bool vis[MAXN];//标记string path[MAXN];//记录路径int cantor(int s[])//康拖展开求该序列的hash值{ 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 Node{ int s[9]; int loc;//“0”的位置 int status;//康拖展开的hash值 string path;//路径};int move[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,rchar indexs[5]="durl";//和上面的要相反,因为是反向搜索int aim=46234;//123456780对应的康拖展开的hash值void bfs(){ memset(vis,false,sizeof(vis)); Node cur,next; for(int i=0;i<8;i++)cur.s[i]=i+1; cur.s[8]=0; cur.loc=8; cur.status=aim; cur.path=""; queue<Node>q; q.push(cur); path[aim]=""; while(!q.empty()) { cur=q.front(); q.pop(); int x=cur.loc/3; int y=cur.loc%3; for(int i=0;i<4;i++) { int tx=x+move[i][0]; int ty=y+move[i][1]; if(tx<0||tx>2||ty<0||ty>2)continue; next=cur; next.loc=tx*3+ty; next.s[cur.loc]=next.s[next.loc]; next.s[next.loc]=0; next.status=cantor(next.s); if(!vis[next.status]) { vis[next.status]=true; next.path=indexs[i]+next.path; q.push(next); path[next.status]=next.path; } } }}int main(){ char ch; Node cur; bfs(); while(cin>>ch) { if(ch=='x') {cur.s[0]=0;cur.loc=0;} else cur.s[0]=ch-'0'; for(int i=1;i<9;i++) { cin>>ch; if(ch=='x') { cur.s[i]=0; cur.loc=i; } else cur.s[i]=ch-'0'; } cur.status=cantor(cur.s); if(vis[cur.status]) { cout<<path[cur.status]<<endl; } else cout<<"unsolvable"<<endl; } return 0;}
4.A*启发搜索
0 0
- 借助八数码问题,双向广搜,康托展开,逆序数奇偶性
- HDU 1043 双向广搜 八数码 康托展开 逆序数
- POJ1077 HDU1043 Eight 八数码第四境界 双向广搜 康托展开 逆康托
- 【双向广搜+逆序数优化】【HDU1043】【八数码】
- 康托展开求八数码问题
- 康托展开(八数码问题)
- 康托展开 双向广搜
- 八数码第六境界——双向BFS+康托展开判重+回溯记录路径+逆序数判无解
- 八数码 康托 逆康托 哈希 双解码 双向广搜
- 双向广搜 八数码
- 【康托展开+状压BFS】poj1077 Eight(八数码问题)
- POJ 1077 Eight 八数码问题[康托展开 + BFS]
- HDU1043BFS 康托展开 八数码
- 八数码(康托展开)
- 八数码第五境界——双向BFS+康托展开判重+回溯记录路径
- 【双向广搜】八数码难题
- poj3131 立体八数码,双向广搜
- 康托展开(逆序数)
- Unix/Linux环境C编程入门教程(42) 终端控制篇
- gcc
- hdu 2096 小明A+B
- DOM树中的节点
- 读书笔记 - 维度建模完全指南
- 借助八数码问题,双向广搜,康托展开,逆序数奇偶性
- poj 1631
- Javase的复习-----9
- Ubuntu下samba的安装设置
- Ubuntu下配置TFTP服务
- Ubuntu下配置NFS服务
- ubuntu下minicom超级终端的使用方法
- ubuntu 下网络配置
- ubuntu下安装wireshark(抓包工具)