soj1091 指环王 bfs+hash+剪枝
原题链接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; }
如有不当之处欢迎指出!
soj1091 指环王 bfs+hash+剪枝的更多相关文章
- NOIP 模拟 玩积木 - 迭代加深搜索 / bfs+hash+玄学剪枝
题目大意: 有一堆积木,0号节点每次可以和其上方,下方,左上,右下的其中一个交换,问至少需要多少次达到目标状态,若步数超过20,输出too difficult 目标状态: 0 1 1 2 2 2 3 ...
- 【BZOJ】1054: [HAOI2008]移动玩具(bfs+hash)
http://www.lydsy.com/JudgeOnline/problem.php?id=1054 一开始我还以为要双向广搜....但是很水的数据,不需要了. 直接bfs+hash判重即可. # ...
- [BZOJ1054][HAOI2008]移动玩具 bfs+hash
1054: [HAOI2008]移动玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2432 Solved: 1355[Submit][Stat ...
- HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)
题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...
- hdu.1067.Gap(bfs+hash)
Gap Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm ...
- BFS+Hash(储存,判重) HDOJ 1067 Gap
题目传送门 题意:一个图按照变成指定的图,问最少操作步数 分析:状态转移简单,主要是在图的存储以及判重问题,原来队列里装二维数组内存也可以,判重用神奇的hash技术 #include <bits ...
- POJ3697+BFS+hash存边
/* 疾速优化+hash存边 题意:给定一个包含N(1 ≤ N ≤ 10,000)个顶点的无向完全图,图中的顶点从1到N依次标号.从这个图中去掉M(0 ≤ M ≤ 1,000,000)条边,求最后与顶 ...
- poj 2046 Gap(bfs+hash)
Description Let's play a card game called Gap. You have cards labeled with two-digit numbers. The fi ...
- poj 2697 A Board Game(bfs+hash)
Description Dao was a simple two-player board game designed by Jeff Pickering and Ben van Buskirk at ...
随机推荐
- linkin大话数据结构--Collections类
操作集合的工具类:Collections Collections 是一个操作 Set.List 和 Map 等集合的工具类.Collections 中提供了大量方法对集合元素进行排序.查询和修改等操作 ...
- Android Acitivy切换平移动画效果实现
1.在anim目录下新建anim文件夹,新建tran_in.xml和tran_out.xml分别表示下一页切换进入,和本页切换出去. 即in表示下一页向左平移,out表示同样向左平移至消失. tran ...
- 获取android手机屏幕的宽高、density
public static String getDisplayMetrics(Context cx) { String str = ""; DisplayMetrics dm = ...
- 【Java SE】如何用Java实现反转排序
摘要:反转排序是将原先已经排序好了的重新排序,是原来的数组元素的顺序反转过来.假设原来的数组顺序是{6,5,4,3,2,1},反转之后的顺序就是{1,2,3,4,5,6}.这个排序的算法不是很难,代码 ...
- centos7+ansible自动化工具使用
一.基础介绍 ========================================================================================== 1. ...
- Storm 对 0.10.x 版 Kafka之commit offsets
由于 0.10.x 版 Kafka 与 0.8.x 版有很大的变化,这种变化对下游 Storm 有非常大的影响,0.10.x 版的 Kafka 不但增加了权限管理的功能,而且还将 simple 和 h ...
- 将常用的Android adb shell 命令行封装为C#静态函数
更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 简介:adb命令是常用的Android命令行,自动化.代码调试.手工排查问题都会用的到,这里将常用的一些命令行封装 ...
- ABP官方文档翻译 4.4 授权
授权 介绍 关于IPermissionChecker 定义权限 检查权限 使用AbpAuthorize特性 AbpAuthorize特性注意点 抑制授权 使用IPermissionChecker 在R ...
- HTTP面试题都在这里
HTTP常见面试题 Http与Https的区别: Http与Https的区别: HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头 HTTP 是不安全的,而 ...
- 剑指offer试题(PHP篇一)
1.二维数组中的查找 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ...