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 ...
随机推荐
- Log4j扩展使用--输出地Appender
OK,现在我们来研究输出低Appended. Appender控制日志输出的位置 Log4j日志系统允许把日志输出到不同的地方,如控制台(Console).文件(Files).根据天数或者文件大小产生 ...
- junit4初体验
OK,现在我们正式开始junit4系列的整理.前面的junit38作为4的补充知道就好了,实际编码中我们以4为主.这里先来一把junit的初体验,同时也让我们来一步一步的了解下TDD的好处. ORM大 ...
- WebSphere--安全性
WebSphere应用服务器具有很好的安全性支持.安全性简单地说就是确定谁可访问重要的系统资源,这些系统资源包括文件.目录.程序.连接和数据库.以独立模式运行WebSphere应用服务器比作为 Web ...
- linkin大话设计模式--常用模式总结
linkin大话设计模式--常用模式总结 一,常用设计模式定义 Abstract Factory(抽象工厂模式):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. Adapter( ...
- finally中关闭资源
对finally中关闭资源是否还要使用try...catch老是感到迷惑,现在存个例子,省的忘了 public StringBuilder readTxtFile(File file){ String ...
- AQS 框架之 LockSupport 线程阻塞工具类
■ 前言 并发包一直是 JDK 里面比较难理解的,同时也是很精美的语言,膜拜下 Doug Li 大神.作者不敢长篇大论,只求循序渐进地把并发包通过理论和实战 (代码) 的方式介绍给大家. 其实做每一件 ...
- libGDX-wiki发布
为方便大家学习和访问,我将libgdx的wiki爬取到doku-wiki下,专门建立了以下地址.欢迎大家来共同完善. http://wiki.v5ent.com
- Swing小技巧总结
1. 使JDialog位于屏幕的中央 public void setToScreenCenter(JDialog jd) { Dimension screenSize = Tool ...
- Linux修改IP永久生效
修改IP永久生效按以下方法: 1)修改配置文件vi /etc/sysconfig/network-scripts/ifcfg-eth0(eth0,第一块网卡,如果是第二块则为eth1) 按如下修改ip ...
- DirectSound---简易Wav播放器
这篇文章主要给大家介绍下如何用DirectSound打造一个简易播放器,因为篇幅有限且代码逻辑较为复杂,我们只介绍下核心技术内容.该播放器主要包括以下功能: 播放.暂停 播放进度提示. 1. Dire ...