soj1091 指环王 bfs+hash+剪枝
来源:互联网 发布:红会福娃娃 知乎 编辑:程序博客网 时间:2024/06/08 03:59
原题链接http://acm.scu.edu.cn/soj/problem.action?id=1091
这题的主要解法就是搜索,我用的是bfs,用map将二维数组处理成字符串作为主键,到达当前状态的最少步数作为键值,就能实现判重,如果当前最少步数已经超过10步,直接退出。但是这样做的时间是1292ms,虽然能够通过,但没能达到最优。
如果能够找到完美的编码函数,就可以不用map,时间应该能够更快,但是25!/12!/12!已经超过了数组的最大容量,找到编码函数也没用了。后来我又想到可以利用剪枝,因为这题限制了10步,设当前的位置不对的棋子数为h(x),当前已经走了y步,如果h(x)+y>10就说明不可能在10步之内完成,直接剪掉。
前面说过,可以把二维数组处理成为字符串作为主键,也可以把二维数组进行二进制压缩,用int作为主键应该会更快。
总之,最大的优化就是剪枝,剪枝后时间为0ms。这题用dfs+剪枝也能过,但没能判重,浪费了不少时间。比赛时,写A*代码应该最为简单。
AC代码:
#include<cstdio>#include<cstring>#include<map>#include<queue>#include<algorithm>using namespace std;const int maxn=30;int goal[][5]={1,1,1,1,1,0,1,1,1,1,0,0,2,1,1,0,0,0,0,1,0,0,0,0,0};const int dx[]={1,1,2,2,-1,-1,-2,-2};const int dy[]={2,-2,1,-1,2,-2,1,-1};int v[maxn];struct node{int x,y;node(){}node(int x,int y):x(x),y(y){}};void deal(){v[0]=1;for(int i=1;i<27;++i) v[i]=2*v[i-1];}inline int get1(int (*a)[5]){ //统计位置不对的棋子 int c=0;for(int i=0;i<5;++i)for(int j=0;j<5;++j){if(a[i][j]==2) continue;else {if(a[i][j]!=goal[i][j]) ++c;}}return c; }int get2(int (*a)[5]){ //二进制的值 int c=0;for(int i=0;i<5;++i)for(int j=0;j<5;++j){c+=a[i][j]*v[i*5+j];}return c;} int get3(int (*a)[5]){ //空地的位置 for(int i=0;i<5;++i)for(int j=0;j<5;++j) if(a[i][j]==2) return i*5+j;}void get4(int (*a)[5],int h,int pos){ //解码 h-=2*v[pos];a[pos/5][pos%5]=2;for(int i=0;i<25;++i){if(i==pos) {h=h>>1;continue;}else {a[i/5][i%5]=h&1;h=h>>1;}}}int bfs(int (*a)[5]){if(get1(a)>10) return -1;map<int,node>ha;queue<int>q;int f=get2(a);q.push(f);ha[f]=node(0,get3(a));while(!q.empty()){int h=q.front();q.pop();int b[5][5];node g=ha[h];get4(b,h,g.y);int d1=get1(b);if(d1+g.x>10) continue;if(d1==0) return g.x;int x=g.y/5,y=g.y%5;int old[5][5];for(int i=0;i<8;++i){int nx=x+dx[i],ny=y+dy[i];if(nx<0||ny<0||nx>=5||ny>=5) continue;memcpy(old,b,sizeof(b));swap(old[x][y],old[nx][ny]);int k=get2(old);if(ha.count(k)) continue;q.push(k);ha[k]=node(ha[h].x+1,get3(old));}}return -1;} int main(){deal();int T;scanf("%d",&T);char ch[5][5];int s[5][5];while(T--){for(int i=0;i<5;++i) scanf("%s",ch[i]);for(int i=0;i<5;++i)for(int j=0;j<5;++j){s[i][j]=ch[i][j]-'0';}int ans=bfs(s);if(ans==-1) printf("Unsolvable in less than 11 move(s).\n");else printf("Solvable in %d move(s).\n",ans);}return 0;}
如有不当之处欢迎指出!
0 0
- soj1091 指环王 bfs+hash+剪枝
- POJ 3985 Knight's Problem(bfs+hash+剪枝)
- HDU1067 Gap( BFS+ HASH 剪枝,矩阵用一个数表示)
- POJ-3985:Knight's Problem(特殊的bfs剪枝以及hash)
- poj 1465 (BFS+剪枝)
- HDU1226-BFS剪枝
- HDU-1548(BFS+剪枝)
- hdu 1175 bfs+剪枝
- PowerOJ1646(BFS+剪枝)
- POJ3278 简单BFS+剪枝
- 点炸弹(bfs+剪枝,或链式向前星+剪枝+bfs)
- BFS+剪枝--hdoj1195(不错)
- hdu 2433 Travel bfs+剪枝
- Nightmare(暴力剪枝BFS)
- fzu2188 过河I BFS+剪枝
- UVA-11882 bfs + dfs + 剪枝
- HDU-1010 bfs+剪枝
- uva 307 bfs优化剪枝
- Linux权限设置
- 自然语言处理学习感悟——感觉自己好笨
- synchronized详解
- centos7+docker综合实验
- 解决服务器不支持emoji表情
- soj1091 指环王 bfs+hash+剪枝
- css中基础padding的小技巧,移动端大用处
- getopt与getopt_long
- ebtables-linux-vyos
- 桶排序:某区间内排序
- SWFUpload在PHP中使用实例
- 快排实现
- class常量池是否引用ref
- js的节点操作:插入,删除,复制,查找节点?