POJ 1077 Eight(据说此题不做人生不完整~~~)
2013-06-19 10:12
357 查看
分析:
八数码问题,典型的搜索题。本题有3个点。一个是搜索方式,一个是判重,一个是状态表示。搜索方法有多种,速度从低到高是bfs,双向bfs,A*,IDA*。POJ的discuss说BFS一般在500MS左右。但是本人只会BFS,就先用了BFS的做法。网上最通俗的做法是用康托展开和逆展开来判重和表示状态,再慢一点的就是用一个数组表示状态。
我是不想用康托展开,又觉得数组太慢。所以想了很久很久,把八数码压缩在一个int里了。哈哈哈,本人独创哦,如有雷同纯属巧合。我的方法是这样的,000表示1,001表示2,以此类推,111表示8。x用000表示,每个数只需要3个位。也许有童鞋问,2个都是用000表示肿么办。这样才用了27个位,最左边5个位指出x的位置。比如12345678x
那么就是 01000 000 001 010 011 100 101 110 111 000。其中01000表示x在从左到右第8位,ps:从0开始,为了方便计算。
我的判重是用hash的,hash函数很简单,直接MOD 1000003。效果还不错,把时间提到了94MS。是不是很帅气啊,哈哈哈。
不过我的状态转移函数写的很差劲,用了很多位运算和乘法操作。期待大牛给出更快的方法。
哦,还有那个打印路线的方法。就是记录之前的一个点。然后递归打印。
代码:
八数码问题,典型的搜索题。本题有3个点。一个是搜索方式,一个是判重,一个是状态表示。搜索方法有多种,速度从低到高是bfs,双向bfs,A*,IDA*。POJ的discuss说BFS一般在500MS左右。但是本人只会BFS,就先用了BFS的做法。网上最通俗的做法是用康托展开和逆展开来判重和表示状态,再慢一点的就是用一个数组表示状态。
我是不想用康托展开,又觉得数组太慢。所以想了很久很久,把八数码压缩在一个int里了。哈哈哈,本人独创哦,如有雷同纯属巧合。我的方法是这样的,000表示1,001表示2,以此类推,111表示8。x用000表示,每个数只需要3个位。也许有童鞋问,2个都是用000表示肿么办。这样才用了27个位,最左边5个位指出x的位置。比如12345678x
那么就是 01000 000 001 010 011 100 101 110 111 000。其中01000表示x在从左到右第8位,ps:从0开始,为了方便计算。
我的判重是用hash的,hash函数很简单,直接MOD 1000003。效果还不错,把时间提到了94MS。是不是很帅气啊,哈哈哈。
不过我的状态转移函数写的很差劲,用了很多位运算和乘法操作。期待大牛给出更快的方法。
哦,还有那个打印路线的方法。就是记录之前的一个点。然后递归打印。
代码:
#include<cstdio> #include<cstring> const int MAXSIZE = 1e6; const int HASHSIZE = 1e6 + 3; const int mask = 1|2|4; int hashTable[HASHSIZE]; int front,rear,cur; void inline lookbit(int x){ for(unsigned i = 1<<31;i;i>>=1) printf("%d",i&x?1:0); printf("\n"); } struct A{ int state,p; char dir; }Q[MAXSIZE]; struct B{ int state,nx; }next[MAXSIZE]; inline int swap(int x, int dist){ int l=x>>27; int t=0; t|=(((x>>(8-(l+dist))*3))&mask)<<(8-l)*3; #ifdef DEBUG lookbit(t); #endif x&=~(mask<<(8-l-dist)*3); #ifdef DEBUG lookbit(x); #endif t|=x; t&=~0U>>5; return t|((l+dist)<<27); } void printAns(int c,int s){ if(Q[c].state != s){ printAns(Q[c].p,s); putchar(Q[c].dir); } } inline int getHashNum(int x){ return x % HASHSIZE; } bool trytoInsert(int x){ int i = getHashNum(x); int l = hashTable[i]; while(l != -1){ if(next[l].state == x) return false; l = next[l].nx; } next[cur].nx = hashTable[i]; next[cur].state = x; hashTable[i] = cur++; return true; } void bfs(int s,int t){ register int temp; Q[rear++].state = s; while(front < rear){ int x = Q[front++].state; if(x==t){ printAns(front-1,s); return; } int z = x>>27; if(z/3>0){ temp = swap(x, -3); if(trytoInsert(temp)){ Q[rear].state = temp; Q[rear].dir = 'u'; Q[rear++].p = front - 1; } } if(z/3<2){ temp = swap(x, 3); if(trytoInsert(temp)){ Q[rear].state = temp; Q[rear].dir = 'd'; Q[rear++].p = front - 1; } } if(z%3>0){ temp = swap(x, -1); if(trytoInsert(temp)){ Q[rear].state = temp; Q[rear].dir = 'l'; Q[rear++].p = front - 1; } } if(z%3<2){ temp = swap(x, 1); if(trytoInsert(temp)){ Q[rear].state = temp; Q[rear].dir = 'r'; Q[rear++].p = front - 1; } } } printf("unsolvable\n"); } int main(){ memset(hashTable,-1,sizeof(hashTable)); char str[2]; int s = 0, t = 0, j = 24; for(int i = 0; i < 9; i++, j -= 3){ scanf("%s",str); if(*str!='x'){ s|=*str-'1'<<j; }else{ s|=i<<27; } } j = 24; t|= 8<<27; for(int i = 0; i < 8; i++, j -= 3){ t|=i<<j; } bfs(s,t); return 0; }
相关文章推荐
- hdu 1034 & poj 1077 Eight 传说中的八数码问题。真是一道神题,A*算法+康托展开
- POJ 1077 Eight 八数码+A* -
- POJ 1077 Eight
- POJ 1077 Eight IDA*
- poj 1077 Eight
- BFS(八数码) POJ 1077 || HDOJ 1043 Eight
- pku 1077 eight(据说有人用8中搜索算法做了这道题目)
- POJ 1077 Eight(康拓展开 BFS 双向BFS)
- poj 1077 + HOJ 10466 + hdu 1043 eight
- POJ 1077 HDU 1043 Eight (IDA*)
- POJ 1077 Eight(八数码A*+IDA*)
- POJ 1077 Eight 八数码问题 A*
- hdu 1043 eight(poj 1077) (bfs)
- POJ 1077 Eight (正向BFS + 康托展开)
- POJ 1077 Eight
- POJ 1077 Eight
- POJ 1077 Eight 八数码 A*搜索算法
- poj 1077-Eight;hdu 1043-Eight
- hdu 1043/poj 1077 Eight (八数码 经典搜索题 bfs + 康托展开)
- HDU 1043 && POJ 1077 Eight (A*)