题解:UVA1604 立体八数码问题 Cubic Eight-Puzzle
题意
有八个方块,每个上面都染了三种颜色,给定开始和最终状态,求最小步数,
分析
本题为八数码问题的加强版。
考虑利用双向 BFS 实现(为了达到平衡,我取了正向
我们利用进制思想来存储状态。立方块有
代码中 dfs 是填充所有可能的 spread 是对状态的扩展。
实现
复杂度
#include<bits/stdc++.h>
using namespace std;
const int N = 10,M = 1680000,op[] = {3,-3,1,-1};
char g[N][N];
int st[2][M][N];
struct node
{
int s,p,step;
}sa;
//s: up/front/right 0-6 wrb wbr rwb rbw bwr brw
int f[][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}};//s1 udlr flip-> s2
queue<node> q[2];
int p;
void dfs(int x,int y,int s)
{
if(x == 3)
{
q[1].push({s,p,1});
st[1][s][p] = 1;
return;
}
if(y == 3)
{
dfs(x + 1,0,s);
return;
}
if(g[x][y] == 'W') dfs(x,y + 1,s * 6),dfs(x,y + 1,s * 6 + 1);
else if(g[x][y] == 'R') dfs(x,y + 1,s * 6 + 2),dfs(x,y + 1,s * 6 + 3);
else if(g[x][y] == 'B') dfs(x,y + 1,s * 6 + 4),dfs(x,y + 1,s * 6 + 5);
else dfs(x,y + 1,s);
}
node get_s(int a[],int step)
{
int s = 0,pos = -1;
for(int i = 0; i < 9; i ++)
if(~a[i]) s = s * 6 + a[i];
else pos = i;
return {s,pos,step};
}
int spread(node x,int o)
{
int s = x.s;
int a[N] = {0},t = 8;
a[x.p] = -1;
while(s)
{
if(t != x.p) a[t] = s % 6,s /= 6;
t --;
}
for(int i = 0; i <= 3; i ++)
{
if(x.p >= 6 && !i || x.p <= 2 && i == 1 || x.p % 3 == 2 && i == 2 || x.p % 3 == 0 && i == 3) continue;
int b = x.p + op[i],c = a[b];
a[x.p] = f[c][i];
a[b] = -1;
node sta = get_s(a,x.step + 1);
if(st[1 - o][sta.s][sta.p]) return x.step + st[1 - o][sta.s][sta.p] - 1;
else if(!st[o][sta.s][sta.p]) st[o][sta.s][sta.p] = x.step + 1,q[o].push(sta);
a[x.p] = -1;
a[b] = c;
}
return -1;
}
int main()
{
int px,py;
while(cin>>py>>px,px || py)
{
memset(st,0,sizeof st);
while(!q[0].empty()) q[0].pop();
while(!q[1].empty()) q[1].pop();
sa = {0,3 * (px - 1) + py - 1,1};
q[0].push(sa);
st[0][0][sa.p] = 1;
for(int i = 0; i < 3; i ++)
for(int j = 0; j < 3; j ++)
{
cin>>g[i][j];
if(g[i][j] == 'E') p = 3 * i + j;
}
dfs(0,0,0);
if(st[1][sa.s][sa.p])
{
puts("0");
continue;
}
bool flag = 0;
while(!q[0].empty() && q[0].front().step <= 20)
{
int v = spread(q[0].front(),0);
if(~v)
{
flag = 1;
printf("%d\n",v);
break;
}
q[0].pop();
}
if(flag) continue;
if(q[0].empty())
{
puts("-1");
continue;
}
while(!q[1].empty() && q[1].front().step <= 10)
{
int v = spread(q[1].front(),1);
if(~v)
{
flag = 1;
printf("%d\n",v);
break;
}
q[1].pop();
}
if(!flag) puts("-1");
}
return 0;
}