题目大意:立体的八数码问题,一次操作是滚动一次方块,问从初始状态到目标状态的最少滚动次数。

题目分析:这道题已知初始状态和目标状态,且又状态数目庞大,适宜用双向BFS。每个小方块有6种状态,整个大方格有9*6^8个状态。每个小方块用一位6进制数表示即可。

注意:状态转移时要谨慎,否则会出现意想不到的错误;

   这道题的末状态有256(2^8)个,如果对搜索层数不加限制,即使双向BFS也会TLE的,当限制正向搜索15层逆向搜索15层至正向搜索27层反向搜索3层时都能AC(我下面贴出的程序是这样的),其中正向搜21层,逆向搜9层时在时间上最高效;

   对于这道题,开辟一个恰当大小的标记数组也能使时间降低一大截;

代码如下:

# include<iostream>
# include<cstdio>
# include<cmath>
# include<map>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std; struct Node
{
int t,n,s;
Node(int _t,int _n,int _s):t(_t),n(_n),s(_s){}
bool operator < (const Node &a) const {
return t>a.t;
}
}; map<char,int>mp;
int ss[8]={1,6,36,216,1296,7776,46656,279936};
int goal[9],path[9],vis[9][1679616],dist[9][1679616];
int d[4][2]={{1,0},{-1,0},{0,-1},{0,1}};
int p[6][4]={
{2,2,5,5},
{4,4,3,3},
{0,0,4,4},
{5,5,1,1},
{1,1,2,2},
{3,3,0,0},
};
priority_queue<Node>q[2]; void dfs(int u,int gp)
{
if(u==9){
int sta=0,cnt=0;
for(int i=0;i<9;++i)
if(path[i]!=-1){
sta=sta+ss[7-cnt]*path[i];
++cnt;
}
dist[gp][sta]=0;
vis[gp][sta]=1;
q[1].push(Node(0,gp,sta));
return ;
}
if(goal[u]==1){
path[u]=0;
dfs(u+1,gp);
path[u]=1;
dfs(u+1,gp);
}else if(goal[u]==2){
path[u]=2;
dfs(u+1,gp);
path[u]=3;
dfs(u+1,gp);
}else if(goal[u]==3){
path[u]=4;
dfs(u+1,gp);
path[u]=5;
dfs(u+1,gp);
}else{
path[u]=-1;
dfs(u+1,gp);
}
} void init(int x,int y)
{
while(!q[0].empty())
q[0].pop();
while(!q[1].empty())
q[1].pop();
memset(dist,-1,sizeof(dist));
memset(vis,-1,sizeof(vis));
dist[x*3+y][0]=0;
vis[x*3+y][0]=0;
q[0].push(Node(0,x*3+y,0));
for(int i=0;i<9;++i)
if(goal[i]==0){
dfs(0,i);
break;
}
} int getv(int p,int s)
{
for(int i=1;i<=8-p;++i)
s/=6;
return s%6;
} int bfs(int id,int step)
{
while(!q[id].empty())
{
Node u=q[id].top();
if(u.t>step)
return -1;
q[id].pop(); if(vis[u.n][u.s]==!id)
return u.t; int gg[9];
int x=u.n/3,y=u.n%3;
for(int i=0;i<4;++i){
int nx=x+d[i][0],ny=y+d[i][1];
if(nx<0||nx>2||ny<0||ny>2)
continue; int s=u.s;
for(int j=8;j>=0;--j){
if(j==u.n)
gg[j]=-1;
else{
gg[j]=s%6;
s/=6;
}
}
gg[u.n]=p[gg[nx*3+ny]][i];
gg[nx*3+ny]=-1;
int sta=0,cnt=0;
for(int j=0;j<9;++j)
if(gg[j]!=-1){
sta=sta+ss[7-cnt]*gg[j];
++cnt;
}
if(vis[nx*3+ny][sta]!=id){
if(vis[nx*3+ny][sta]==-1){
vis[nx*3+ny][sta]=id;
dist[nx*3+ny][sta]=u.t+1;
q[id].push(Node(u.t+1,nx*3+ny,sta));
}
else
return u.t+1+dist[nx*3+ny][sta];
}
}
}
return -1;
} int solve()
{
int step=0;
while(!q[0].empty()||!q[1].empty()){
if(step>30)
return -1;
if(!q[0].empty()&&step<=21){
int k=bfs(0,step);
if(k>30)
return -1;
if(k!=-1)
return k;
}
if(!q[1].empty()&&step<=9){
int k=bfs(1,step);
if(k>30)
return -1;
if(k!=-1)
return k;
}
++step;
}
return -1;
} int main()
{
//freopen("UVA-1604 Cubic Eight-Puzzle.txt","r",stdin);
mp['E']=0,mp['W']=1,mp['R']=2,mp['B']=3;
int x,y,gx,gy;
char s[2];
while(scanf("%d%d",&y,&x)&&(x+y))
{
--x,--y;
for(int i=0;i<9;++i){
scanf("%s",s);
goal[i]=mp[s[0]];
}
init(x,y);
printf("%d\n",solve());
}
return 0;
}

  

UVA-1604 Cubic Eight-Puzzle (双向BFS+状态压缩+限制搜索层数)的更多相关文章

  1. ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))

    求一条蛇到(1,1)的最短路长,题目不简单,状态较多,需要考虑状态压缩,ZOJ的数据似乎比POj弱一些 POJ1324(ZOJ1361)-Holedox Moving 题意:一条已知初始状态的蛇,求其 ...

  2. HDU1429+bfs+状态压缩

    bfs+状态压缩思路:用2进制表示每个钥匙是否已经被找到.. /* bfs+状态压缩 思路:用2进制表示每个钥匙是否已经被找到. */ #include<algorithm> #inclu ...

  3. BFS+状态压缩 hdu-1885-Key Task

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1885 题目意思: 给一个矩阵,给一个起点多个终点,有些点有墙不能通过,有些点的位置有门,需要拿到相应 ...

  4. poj 1753 Flip Game(bfs状态压缩 或 dfs枚举)

    Description Flip game squares. One side of each piece is white and the other one is black and each p ...

  5. BFS+状态压缩 HDU1429

    胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  6. hdoj 5094 Maze 【BFS + 状态压缩】 【好多坑】

    Maze Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Sub ...

  7. HDU 3247 Resource Archiver (AC自己主动机 + BFS + 状态压缩DP)

    题目链接:Resource Archiver 解析:n个正常的串.m个病毒串,问包括全部正常串(可重叠)且不包括不论什么病毒串的字符串的最小长度为多少. AC自己主动机 + bfs + 状态压缩DP ...

  8. HDU 1885 Key Task (BFS + 状态压缩)

    题意:给定一个n*m的矩阵,里面有门,有钥匙,有出口,问你逃出去的最短路径是多少. 析:这很明显是一个BFS,但是,里面又有其他的东西,所以我们考虑状态压缩,定义三维BFS,最后一维表示拿到钥匙的状态 ...

  9. hdu 1429(bfs+状态压缩)

    题意:容易理解,但要注意的地方是:如果魔王回来的时候刚好走到出口或还未到出口都算逃亡失败.因为这里我贡献了一次wa. 分析:仔细阅读题目之后,会发现最多的钥匙数量为10把,所以把这个作为题目的突破口, ...

随机推荐

  1. 聊一聊goroutine stack

    通过阅读这篇文章对内存的处理以及栈的扩容有了新的认识,我们在生产环境中也遇到了内存使用量超大的情况,现在怀疑也可能是由于栈扩容导致的 很好的一片文章: 推送在外卖订餐中扮演着重要的角色,为商家实时接单 ...

  2. django基础之FBV与CBV,ajax序列化补充,Form表单

    目录: FBV与CBV ajax序列化补充 Form表单(一) 一.FBV与CBV 1.什么是FBV.CBV? django书写view时,支持两种格式写法,FBV(function bases vi ...

  3. c primer plus(五版)编程练习-第七章编程练习

    1.编写一个程序.该程序读取输入直到遇到#字符,然后报告读取的空格数目.读取的换行符数目以及读取的所有其他字符数目. #include<stdio.h> #include<ctype ...

  4. Swagger生成的接口需要权限验证的处理方法

    通常开发API的时候需要对接口进行权限验证,而我们在使用Swagger生成接口文档界面的时候,直接调用需要权限验证的接口会提示"当前用户没有登陆" 为了解决此问题,我们需要更改一下 ...

  5. cocos代码研究(12)UI之Widget学习笔记

    理论基础 Widget类,所有UI控件的基类. 这类继承自ProtectedNode和LayoutParameterProtocol. 如果你想实现自己的UI控件,你应该继承这个类. 被 VideoP ...

  6. java之类适配器

    类适配器 所谓类适配器,指的是适配器Adapter继承我们的被适配者Adaptee,并实现目标接口Target.由于Java中是单继承,所以这个适配器仅仅只能服务于所继承的被适配者Adaptee.代码 ...

  7. uva1351 dp

    这题说的是给了 一个串 然后 比如 aaaaabbbbbbcdddd 可以化成5(a)6(b)c4(d) 这样的串明显 长度更短了 , 请 计算出使得这个串最短的 长度是多少, dp[i][j] 表示 ...

  8. Java String、StringBuffer、StringBuilder有什么区别

    ① String是Java语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑.它是典型的immutable类,被声明成final class,所有属性也都是final的,由于它的不可变性,类 ...

  9. iptable的使用

    目录 iptables iptables iptables详解 2012-07-18 20:10:08 分类: LINUX 一:前言 防火墙,其实说白了讲,就是用于实现Linux下访问控制的功能的,它 ...

  10. VC++使用HOOK API 屏蔽PrintScreen键截屏以及QQ和微信默认热键截屏

    转载:http://blog.csdn.net/easysec/article/details/8833457 转载:http://www.vckbase.com/module/articleCont ...