题意:

初始状态固定(朝上的全是W,空格位置输入给出),输入初始状态的空格位置,和最终状态朝上的位置,输出要多少步才能移动到,超过30步输出-1.

简析:

每一个格子有6种状态,分别是

0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR (上前后 对应的颜色)

由于只给出了终态朝上的颜色,其他的不知道,所以终态真正应该有256种,对于这个可以用一次dfs全部枚举出。

一、

搜索策略的问题

单向搜索的话,平均一下,大概每次也有3个状态,30层的话,复杂度太高,放弃。

A*的话,考虑当前不在正确位置的格子数。不知道是否可行,没有尝试。

双向搜索的话,只有30层,平分一下15层,再看看时间5s,还是可以接受的。而考虑到最终状态有256个,所以反向扩展的速度非常快,所以我们可以让

反向搜索只进行10层左右,保持2边平衡达到最佳速度。

二、

考虑判重的问题

由上面的分析可知,判重可以选择2种方式。

1、用一个6进制可以存下所有非空格的情况,再加一个空格的位置也就是6^8*9=15116544这么大的数组,双向搜索的话,也就是这个的2倍大的数组。

2、用一个7进制存下所有情况7^9-1=40353607,双向搜索的话,就是2倍………接近1亿。

第二种果断放弃了。。。

三、

hash值计算的问题

显然初始情况的hash要 s[0]*6^0+s[1]*6^1+......,但如果以后每次我们都用一个for(0---9)的循环计算的话,时间复杂度太高。

分析后发,每移动一次,左右移动的话,只会改变1个位置的值,上下移动的话只会改变3个位置的值,所以我们就计算这几个改变的值就够了。

四、

STL的使用,我测试了一下,不用STL的话速度可以快1000ms左右,但是内存就不好把握了,在上面都考虑到的情况下,用STL也不会影响AC。

给出STL版本的

include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std; // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR int base[]={1,6,36,216,1296,7776,46656,279936,1679616};
int state[6][4]={{2,2,4,4},{5,5,3,3},{0,0,5,5},{4,4,1,1},{3,3,0,0},{1,1,2,2}};
char hash1[1680000][9];
char hash2[1680000][9];
char b[10];
struct node
{
int s[9];
int dis;
int space;
int value;
}st;
queue<node> q;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //下,上,右,左,和前面相反 inline bool isok(int &x,int &y)
{
return x>=0&&x<3&&y>=0&&y<3;
}
inline int cal(node &t) //计算初始的hash值
{
int value=0;
int top=0;
for(int i=0;i<9;i++)
{
if(i==t.space) continue;
value+=t.s[i]*base[top++];
}
return value;
}
int cal(node &t,node &f,int d) //因为每次移动只会改变几个hash值,所以可以特判
{
if(d==2)
{
t.value-=f.s[t.space]*base[f.space];
t.value+=t.s[f.space]*base[f.space];
return t.value;
}
else if(d==3)
{
t.value-=f.s[t.space]*base[t.space];
t.value+=t.s[f.space]*base[t.space];
return t.value;
}
else if(d==0)
{
for(int i=f.space;i<=f.space+2;i++)
{
t.value-=f.s[i+1]*base[i];
t.value+=t.s[i]*base[i];
}
return t.value;
}
else if(d==1)
{
for(int i=t.space;i<=t.space+2;i++)
{
t.value-=f.s[i]*base[i];
t.value+=t.s[i+1]*base[i];
}
return t.value;
}
}
bool bfs(node st)
{
node t1,t2,f;
queue<node> Q;
st.dis=0;
Q.push(st);
t2.dis=0;
int k;
int k1=1,kk1=0,k2=256,kk2=0;
while(!Q.empty()&&!q.empty())
{
while(k1--){
st=Q.front();Q.pop();
if(st.dis+1+t2.dis>30) {printf("-1\n");return false;}
for(int d=0;d<4;d++)
{
t1=st;
int sx=t1.space/3;
int sy=t1.space%3;
int nx=sx+dir[d][0];
int ny=sy+dir[d][1];
if(isok(nx,ny))
{
t1.space=nx*3+ny;
t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];
t1.s[nx*3+ny]=6;
t1.dis=st.dis+1;
t1.value=cal(t1,st,d);
if(hash1[t1.value][t1.space]) continue;
if(hash2[t1.value][t1.space]) {printf("%d\n",t1.dis+t2.dis);return true;} hash1[t1.value][t1.space]=t1.dis;
Q.push(t1);
kk1++;
}
}
}
k1=kk1;
kk1=0;
while(k2--){
f=q.front();
if(f.dis==9) break;
q.pop();
for(int d=0;d<4;d++)
{
t2=f;
int sx=t2.space/3;
int sy=t2.space%3;
int nx=sx+dir[d][0];
int ny=sy+dir[d][1];
t2.dis=f.dis+1;
if(isok(nx,ny))
{
t2.space=nx*3+ny;
t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];
t2.s[nx*3+ny]=6;
t2.value=cal(t2,f,d);
if(hash2[t2.value][t2.space]) continue;
if(hash1[t2.value][t2.space])
{
printf("%d\n",t2.dis+st.dis+1);
return true;
}
hash2[t2.value][t2.space]=t2.dis;
q.push(t2);
kk2++;
}
}
}
t1.dis=f.dis+1;
k2=kk2;
kk2=0;
}
printf("-1\n");
}
void dfs(node &end,int k)
{
if(k==9)
{
end.dis=0;
end.value=cal(end);
q.push(end);
hash2[end.value][end.space]=1;
return;
}
if(b[k]=='W')
{
end.s[k]=0;
dfs(end,k+1);
end.s[k]=1;
dfs(end,k+1);
}
else if(b[k]=='R')
{
end.s[k]=2;
dfs(end,k+1);
end.s[k]=3;
dfs(end,k+1);
}
else if(b[k]=='B')
{
end.s[k]=4;
dfs(end,k+1);
end.s[k]=5;
dfs(end,k+1);
}
else
{
end.s[k]=6;
dfs(end,k+1);
}
}
int main()
{
int x,y;
char a;
node end;
while(scanf("%d%d",&y,&x)!=EOF)
{
if(!x&&!y) break;
while(!q.empty()) q.pop();
memset(hash1,0,sizeof(hash1));
memset(hash2,0,sizeof(hash2)); x--;y--;
for(int i=0;i<9;i++)
{
if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}
else st.s[i]=0;
}
for(int i=0;i<9;i++)
{
scanf(" %c",&a);
if(a=='E') end.space=i;
b[i]=a;
}
dfs(end,0); //得到所有的终点状态,全部加入队列。 int k; //一开始就是答案
st.value=cal(st);
hash1[st.value][st.space]=-1;
if(hash2[st.value][st.space]) {printf("0\n");continue;}
bfs(st);
}
return 0;
}

再给出静态数组版本

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; // 0WRB, 1WBR, 2RWB, 3RBW, 4BRW, 5BWR int base[]={1,6,36,216,1296,7776,46656,279936,1679616};
int state[6][4]={{2,2,4,4},{5,5,3,3},{0,0,5,5},{4,4,1,1},{3,3,0,0},{1,1,2,2}};
char hash1[1680000][9];
char hash2[1680000][9];
char b[10];
struct node
{
int s[9];
int dis;
int space;
int value;
}q1[300000],q2[100005],st;
int r2;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //下,上,右,左,和前面相反 inline bool isok(int &x,int &y)
{
return x>=0&&x<3&&y>=0&&y<3;
}
inline int cal(node &t) //计算初始的hash值
{
int value=0;
int top=0;
for(int i=0;i<9;i++)
{
if(i==t.space) continue;
value+=t.s[i]*base[top++];
}
return value;
}
int cal(node &t,node &f,int d) //因为每次移动只会改变几个hash值,所以可以特判
{
if(d==2)
{
t.value-=f.s[t.space]*base[f.space];
t.value+=t.s[f.space]*base[f.space];
return t.value;
}
else if(d==3)
{
t.value-=f.s[t.space]*base[t.space];
t.value+=t.s[f.space]*base[t.space];
return t.value;
}
else if(d==0)
{
for(int i=f.space;i<=f.space+2;i++)
{
t.value-=f.s[i+1]*base[i];
t.value+=t.s[i]*base[i];
}
return t.value;
}
else if(d==1)
{
for(int i=t.space;i<=t.space+2;i++)
{
t.value-=f.s[i]*base[i];
t.value+=t.s[i+1]*base[i];
}
return t.value;
}
}
bool bfs(node st)
{
node t1,t2,f;
int r1=0,f1=0,f2=0;
st.dis=0;
q1[r1++]=st;
t2.dis=0;
int k;
int k1=1,kk1=0,k2=256,kk2=0;
while(f1<r1&&f2<r2)
{
while(k1--){
st=q1[f1];
if(st.dis+1+t2.dis>30) {printf("-1\n");return false;}
for(int d=0;d<4;d++)
{
t1=st;
int sx=t1.space/3;
int sy=t1.space%3;
int nx=sx+dir[d][0];
int ny=sy+dir[d][1];
if(isok(nx,ny))
{
t1.space=nx*3+ny;
t1.s[sx*3+sy]=state[t1.s[nx*3+ny]][d];
t1.s[nx*3+ny]=6;
t1.dis=st.dis+1;
t1.value=cal(t1,st,d);
if(hash1[t1.value][t1.space]) continue;
if(hash2[t1.value][t1.space]) {printf("%d\n",t1.dis+t2.dis);return true;} hash1[t1.value][t1.space]=t1.dis;
q1[r1++]=t1;
kk1++;
}
}
f1++;
}
k1=kk1;
kk1=0;
while(k2--){
f=q2[f2];
if(f.dis==8) break; //超过这个,反向就不搜了,
for(int d=0;d<4;d++)
{
t2=f;
int sx=t2.space/3;
int sy=t2.space%3;
int nx=sx+dir[d][0];
int ny=sy+dir[d][1];
t2.dis=f.dis+1;
if(isok(nx,ny))
{
t2.space=nx*3+ny;
t2.s[sx*3+sy]=state[t2.s[nx*3+ny]][d];
t2.s[nx*3+ny]=6;
t2.value=cal(t2,f,d);
if(hash2[t2.value][t2.space]) continue;
if(hash1[t2.value][t2.space])
{
printf("%d\n",t2.dis+st.dis+1);
return true;
}
hash2[t2.value][t2.space]=t2.dis;
q2[r2++]=t2;
kk2++;
}
}
f2++;
} t1.dis=f.dis+1;
k2=kk2;
kk2=0;
}
printf("-1\n");
}
void dfs(node &end,int k)
{
if(k==9)
{
end.dis=0;
end.value=cal(end);
q2[r2++]=end;
hash2[end.value][end.space]=1;
return;
}
if(b[k]=='W')
{
end.s[k]=0;
dfs(end,k+1);
end.s[k]=1;
dfs(end,k+1);
}
else if(b[k]=='R')
{
end.s[k]=2;
dfs(end,k+1);
end.s[k]=3;
dfs(end,k+1);
}
else if(b[k]=='B')
{
end.s[k]=4;
dfs(end,k+1);
end.s[k]=5;
dfs(end,k+1);
}
else
{
end.s[k]=6;
dfs(end,k+1);
}
}
int main()
{
int x,y;
char a;
node end;
while(scanf("%d%d",&y,&x)!=EOF)
{
if(!x&&!y) break;
memset(hash1,0,sizeof(hash1));
memset(hash2,0,sizeof(hash2));
r2=0;
x--;y--;
for(int i=0;i<9;i++)
{
if(x==i/3&&y==i%3) {st.s[i]=6;st.space=i;}
else st.s[i]=0;
}
for(int i=0;i<9;i++)
{
scanf(" %c",&a);
if(a=='E') end.space=i;
b[i]=a;
}
dfs(end,0); //得到所有的终点状态,全部加入队列。 int k; //一开始就是答案
st.value=cal(st);
hash1[st.value][st.space]=-1;
if(hash2[st.value][st.space]) {printf("0\n");continue;}
bfs(st);
}
return 0;
}

poj 3131 双向搜索+hash判重的更多相关文章

  1. codevs 1004 四子连棋 BFS、hash判重

    004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold       题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋 ...

  2. poj 3131 Cubic Eight-Puzzle 双向广搜 Hash判重

    挺不错的题目,很锻炼代码能力和调试能力~ 题意:初始格子状态固定,给你移动后格子的状态,问最少需要多少步能到达,如果步数大于30,输出-1. 由于单向搜索状态太多,搜到二十几就会爆了,所以应该想到双向 ...

  3. POJ 3263 差分+set判重

    题意: 思路: 对于每一个区间 [a,b] [a+1,b-1]肯定是比a,b低至少1的 因为题目要求最大值 所以就直接差分一下 搞之 (复杂度 O(n)) Discuss里说有重复的数据 用set判一 ...

  4. BFS以及hash表判重的应用~

    主要还是讲下hash判重的问题吧 这道题目用的是除法求余散列方式 前几天看了下算法导论 由于我们用的是线性再寻址的方式来解决冲突问题 所以hash表的大小(余数的范围)要包含我们要求的范围 对mod的 ...

  5. poj 1564 Sum It Up | zoj 1711 | hdu 1548 (dfs + 剪枝 or 判重)

    Sum It Up Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Sub ...

  6. BFS+Hash(储存,判重) HDOJ 1067 Gap

    题目传送门 题意:一个图按照变成指定的图,问最少操作步数 分析:状态转移简单,主要是在图的存储以及判重问题,原来队列里装二维数组内存也可以,判重用神奇的hash技术 #include <bits ...

  7. 关于八数码问题中的状态判重的三种解决方法(编码、hash、&lt;set&gt;)

    八数码问题搜索有非常多高效方法:如A*算法.双向广搜等 但在搜索过程中都会遇到同一个问题.那就是判重操作(假设反复就剪枝),怎样高效的判重是8数码问题中效率的关键 以下关于几种判重方法进行比較:编码. ...

  8. POJ 1945 暴搜+打表 (Or 暴搜+判重)

    思路: 呃呃 暴搜+打表 暴搜的程序::稳稳的TLE+MLE (但是我们可以用来打表) 然后我们就可以打表过了 hiahiahia 可以证明最小的那个数不会超过200(怎么证明的我也不知道),然后就直 ...

  9. POJ 2458 DFS+判重

    题意: 思路: 搜+判重 嗯搞定 (听说有好多人用7个for写得-.) //By SiriusRen #include <bitset> #include <cstdio>0 ...

随机推荐

  1. 《深入理解Java虚拟机》笔记--第二章、Java内存区域与内存溢出异常

    Java程序员把内存的控制权交给了Java虚拟机.在Java虚拟机内存管理机制的帮助下,程序员不再需要为每一个new操作写对应的delete/free代码,而且不容易出现内存泄露和溢出. 虚拟机在执行 ...

  2. java版云笔记(五)

    下来是创建笔记本,创建笔记,这个没什么难点和前面是一样的. 创建笔记本 首先点击"+"弹出添加笔记的对话框,然后点击确定按钮创建笔记本. //点击"+"弹出添加 ...

  3. 冒泡法的算法最佳情况下的时间复杂度为什么是O(n)

    我在许多书本上看到冒泡排序的最佳时间复杂度是O(n),即是在序列本来就是正序的情况下. 但我一直不明白这是怎么算出来的,因此通过阅读<算法导论-第2版>的2.2节,使用对插入排序最佳时间复 ...

  4. 小技巧:tar命令打包目录时,排除文件和目录的命令

    今天不巧要用上,百度. tar zcvf fd.tar.gz pardir --exclude=pardir/file1 --exclude=pardir/dir1

  5. 找到最大或最小的N个元素---heapq模块

    堆排序heapq的用法 基本用法: 复杂数据结构: # coding=utf- # example.py # Example of using heapq to find the N smallest ...

  6. vue框架muse-ui官网文档主题错误毕竟【01】

    在使用了element-ui后,总觉得不尽兴,再学一个响应式的muse-ui发现是个小众框架,但是我很喜欢. 指出官网文档里的主题使用描述错误. 首先,在vue-cli里安装raw-loader:np ...

  7. LoadRunner项目结合抓包工具

    LoadRunner项目结合抓包工具 常见的抓包工具包括:     1. Http协议   报文分为"请求","应答"两大类. 请求: 方法-URL-协议/版本 ...

  8. ref:ubuntu下如何批量修改文件后缀名

    ref:https://blog.csdn.net/whuslei/article/details/6724900 ubuntu下如何批量修改文件后缀名 正确的方法是: 在命令行中输入   renam ...

  9. 《java虚拟机》----类加载机制

    No1: 实现语言无关性的基础仍然是虚拟机和字节码存储格式,虚拟机只与Class文件这种特定的二进制文件格式所关联,并不关心Class的来源是何种语言. No2: Class文件是一组以8位字节为基础 ...

  10. 洛谷P4151 [WC2011] 最大XOR和路径 [线性基,DFS]

    题目传送门 最大XOR和路径 格式难调,题面就不放了. 分析: 一道需要深刻理解线性基的题目. 好久没打过线性基的题了,一开始看到这题还是有点蒙逼的,想了几种方法全被否定了.还是看了大佬的题解才会做的 ...