POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)
Description
Let’s play a puzzle using eight cubes placed on a 3 × 3 board leaving one empty square.
Faces of cubes are painted with three colors. As a puzzle step, you can roll one of the cubes to a adjacent empty square. Your goal is to make the specified color pattern visible from above by a number of such steps.
The rules of this puzzle are as follows.
Coloring of Cubes: All the cubes area colored in the same way as shown in Figure 1. The opposite faces have the same color.
Figure 1: Coloring of a cube
Initial Board State: Eight cubes are placed on the 3 × 3 board leaving one empty square. All the cubes have the same orientation as shown in Figure 2. As shown in the figure, squares on the board are given x and y coordinates,
(1, 1), (1, 2), …, and (3, 3). The position of the initially empty square may vary.Figure 2: Initial board state
Rolling Cubes: At each step, we can choose one of the cubes adjacent to the empty square and roll it into the empty square, leaving the original position empty. Figure 3 shows an example.
Figure 3: Rolling a cube
Goal: The goal of this puzzle is to arrange the cubes so that their top faces form the specified color pattern by a number of cube rolling steps described above.
Your task is to write a program that finds the minimum number of steps required to make the specified color pattern from the given initial state.
Input
The input is a sequence of datasets. The end of the input is indicated by a line containing two zeros separated by a space. The number of datasets is less than 16. Each dataset is formatted as follows.
x y F11 F21 F31 F12 F22 F32 F13 F23 F33
The first line contains two integers x and y separated by a space, indicating the position (x, y) of the initially empty square. The values of x and y are 1, 2, or 3.
The following three lines specify the color pattern to make. Each line contains three characters F1j, F2j, and F3j, separated by a space. Character Fij indicates
the top color of the cube, if any, at the position (i, j) as follows:
B:
Blue,
W:
White,
R:
Red,
E:
the square is Empty.
There is exactly one ‘E
’ character in each dataset.
Output
For each dataset, output the minimum number of steps to achieve the goal, when the goal can be reached within 30 steps. Otherwise, output “-1
” for the dataset.
Sample Input
1 2
W W W
E W W
W W W
2 1
R B W
R W W
E W W
3 3
W B W
B R E
R B R
3 3
B W R
B W R
B E R
2 1
B B B
B R B
B R E
1 1
R R R
W W W
R R E
2 1
R R R
B W B
R R E
3 2
R R R
W E W
R R R
0 0
Sample Output
0
3
13
23
29
30
-1
-1
Source
思路:数据太大,先抽象出状态,再哈希一下,然后就是双向BFS。
#include <stdio.h>
#include <string.h>
#include <stack>
using namespace std;
#define INF 99999999
struct{
int step,state;
}t,que1[1000000],que2[1000000];
stack<int>stk;
bool vis1[5000007],vis2[5000007];
int top1,top2,bottom1,bottom2,mp[9],nxt[2][7]={{0,4,6,5,1,3,2},{0,5,3,2,6,1,4}},head[5000007],next[5000007],val[5000007],total;
int hashval(int x)
{
int t,i;
t=x%5000007;
for(i=head[t];i!=-1;i=next[i])
{
if(val[i]==x) return i;
}
val[total]=x;
next[total]=head[t];
head[t]=total;
total++;
return total-1;
}
void pushtarget(int cnt,int state)
{
if(cnt==-1)
{
vis2[hashval(state)]=1;
que2[bottom2].step=0;
que2[bottom2].state=state;
bottom2++;
return;
}
if(mp[cnt]%2)
{
pushtarget(cnt-1,state*7+mp[cnt]);
pushtarget(cnt-1,state*7+mp[cnt]+1);
}
else pushtarget(cnt-1,state*7);
}
int getstate()
{
int temp=0;
for(int i=8;i>=0;i--)
{
temp=temp*7+mp[i];
}
return temp;
}
void spread(int x)
{
int i=0,temp,cnt,old;
while(i<9)
{
if(x%7==0) cnt=i;
mp[i++]=x%7;
x/=7;
}
cnt+=1;
if(cnt>=0 && cnt<9 && cnt%3>0)
{
old=mp[cnt];
mp[cnt-1]=nxt[0][mp[cnt]];
mp[cnt]=0;
stk.push(getstate());
mp[cnt]=old;
mp[cnt-1]=0;
}
cnt-=1;
cnt-=1;
if(cnt>=0 && cnt<9 && cnt%3<2)
{
old=mp[cnt];
mp[cnt+1]=nxt[0][mp[cnt]];
mp[cnt]=0;
stk.push(getstate());
mp[cnt]=old;
mp[cnt+1]=0;
}
cnt+=1;
cnt-=3;
if(cnt>=0 && cnt<9)
{
old=mp[cnt];
mp[cnt+3]=nxt[1][mp[cnt]];
mp[cnt]=0;
stk.push(getstate());
mp[cnt]=old;
mp[cnt+3]=0;
}
cnt+=3;
cnt+=3;
if(cnt>=0 && cnt<9)
{
old=mp[cnt];
mp[cnt-3]=nxt[1][mp[cnt]];
mp[cnt]=0;
stk.push(getstate());
mp[cnt]=old;
mp[cnt-3]=0;
}
cnt-=3;
}
int bfs()
{
int step1=0,step2=0,ans=INF,temp;
for(step1=0;step1<=20;step1++)
{
while(top1<bottom1 && que1[top1].step==step1)
{
spread(que1[top1].state);
while(!stk.empty())
{
temp=stk.top();
stk.pop();
if(vis2[hashval(temp)])
{
return step1+step2+1;
}
if(!vis1[hashval(temp)])
{
vis1[hashval(temp)]=1;
que1[bottom1].state=temp;
que1[bottom1].step=que1[top1].step+1;
bottom1++;
}
}
top1++;
}
while(top2<bottom2 && que2[top2].step==step2 && step2<9)
{
spread(que2[top2].state);
while(!stk.empty())
{
temp=stk.top();
stk.pop();
if(vis1[hashval(temp)]) return step1+step2+2;
if(!vis2[hashval(temp)])
{
vis2[hashval(temp)]=1;
que2[bottom2].state=temp;
que2[bottom2].step=step2+1;
bottom2++;
}
}
top2++;
}
if(step2<9) step2++;
}
return -1;
}
int main()
{
int x,y,i,j,temp;
char ctemp;
while(~scanf("%d%d",&y,&x) && x)
{
x--;
y--;
top1=top2=bottom1=bottom2=0;
memset(vis1,0,sizeof vis1);
memset(vis2,0,sizeof vis2);
memset(head,-1,sizeof head);
total=0;
while(!stk.empty()) stk.pop();
for(i=0;i<9;i++)
{
ctemp=getchar();
if(ctemp=='\n' || ctemp==' ')
{
i--;
continue;
}
if(ctemp=='W')mp[i]=1;
else if(ctemp=='B') mp[i]=3;
else if(ctemp=='R') mp[i]=5;
else if(ctemp=='E') mp[i]=0;
}
pushtarget(8,0);
temp=0;
for(i=8;i>=0;i--)
{
if(i!=x*3+y) temp=temp*7+1;
else temp*=7;
}
if(vis2[hashval(temp)])
{
printf("0\n");
continue;
}
vis1[hashval(temp)]=1;
que1[bottom1].step=0;
que1[bottom1].state=temp;
bottom1++;
printf("%d\n",bfs());
}
}
POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)的更多相关文章
- UVA-1604 Cubic Eight-Puzzle (双向BFS+状态压缩+限制搜索层数)
题目大意:立体的八数码问题,一次操作是滚动一次方块,问从初始状态到目标状态的最少滚动次数. 题目分析:这道题已知初始状态和目标状态,且又状态数目庞大,适宜用双向BFS.每个小方块有6种状态,整个大方格 ...
- poj 3131 Cubic Eight-Puzzle 双向广搜 Hash判重
挺不错的题目,很锻炼代码能力和调试能力~ 题意:初始格子状态固定,给你移动后格子的状态,问最少需要多少步能到达,如果步数大于30,输出-1. 由于单向搜索状态太多,搜到二十几就会爆了,所以应该想到双向 ...
- POJ 1915 经典马步 双向bfs
拿这个经典题目开刀...........可是双向时间优势在这题上的效果不太明显 #include <iostream> #include <algorithm> #includ ...
- Eight (HDU - 1043|POJ - 1077)(A* | 双向bfs+康拓展开)
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...
- POJ 3170 Knights of Ni (暴力,双向BFS)
题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...
- POJ 1915-Knight Moves (单向BFS && 双向BFS 比)
主题链接:Knight Moves 题意:8个方向的 马跳式走法 ,已知起点 和终点,求最短路 研究了一下双向BFS,不是非常难,和普通的BFS一样.双向BFS只是是从 起点和终点同一时候開始搜索,可 ...
- [poj] 2549 Sumsets || 双向bfs
原题 在集合里找到a+b+c=d的最大的d. 显然枚举a,b,c不行,所以将式子移项为a+b=d-c,然后双向bfs,meet int the middle. #include<cstdio&g ...
- POJ——3126Prime Path(双向BFS+素数筛打表)
Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16272 Accepted: 9195 Descr ...
随机推荐
- sama5d36 OUT0-OUT3 对应关系 带光模块的系统
ARM-IO9 PA8 OUT0 ARM-IO10 PA1 OUT1 ARM-IO11 PA3 OUT2 ARM-IO12 PA9 OUT3
- sama5d3 环境检测 adc测试
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h># ...
- asp.net treeview 总结
网上关于Treeview的代码虽然多 但是都是很乱 实用性和正确性也不是很好 只好自己写一套了,时间比较紧张 性能可能还需调整 以用户组织的一个实际例子来讲诉Treeview的用法吧 组织表结构: 用 ...
- JsonNode、JsonObject常用方法
最近项目中要用json,闲暇时间,对json进行下总结. 1.JsonNode 项目中用到的jar包 import com.fasterxml.jackson.core.JsonParseExce ...
- MySQL线程池总结
线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应用服务还是DB服务,高并发请求始终是一个绕不开的话题.当有大量请求并发访问时,一定伴随着资源的不断创建和释放,导致资源利用率低 ...
- php if语句判定my查询是否为空
<?php header("Content-type: text/html; charset=utf-8"); $username=$_GET['username']; $p ...
- 关于Unity中的.meta文件
.meta文件是用于辅助管理Unity资源文件的文件,删除后,Unity会自动生成,里面记录了各个资源Inspector的信息,属性等等,Unity是不会改变源资源文件的,没有意义,它是靠.meta文 ...
- vim 编辑器使用技巧
看着李立鹏熟练的使用vim,哥心里痒痒的,也来试试! vim pkf.txt i 插入编辑 esc -> :x //退出保存 f8 ->//进入多窗口模式 以下是其他命令: 命令历史 以: ...
- ThinkPHP项目笔记之RBAC(权限)补充篇
这里,主要补充的是配置以及相关代码问题. <?php return array( //'配置项'=>'配置值' 'RBAC_SUPERADMIN' => 'admin',//超级管理 ...
- 关于js中遍历总结
1.for循环 var arr = []; for (var i = 0; i < arr.length; i++) { if (条件1) return; if (条件2) break; if ...