您的位置:首页 > 其它

UVA_Cubic Eight-Puzzle UVA 1604

2015-05-04 12:09 363 查看
Let's play a puzzle using eight cubes placed on a 3 x 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 the 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.
[b]Coloring of Cubes:
All the cubes are colored in the same way as shown in Figure 3. The opposite
faces have the same color.
Figure 3: Coloring of a cube[/b]




[b]1.Initial Board State:
Eight cubes are placed on the 3 x 3 board leaving one empty square. All the
cubes have the same orientation as shown in Figure 4. 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.[/b]


Figure 4: Initial board state
[b]2.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 5 shows an example.
Figure 5: Rolling a cube[/b]





[b]3.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.
4.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
F
11 F21 F31
F
12 F22 F32
F
13 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
F
3j, separated by a space. Character Fij indicates the top color of the cube, if any, at 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.
3618 - Cubic Eight-Puzzle 2/3
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

[/b]

解题报告

难度。。很大,BFS这个没有疑问,那么究竟是A*还是双广呢,由于本题的状态数很多,且转移方程很麻烦,所以首先考虑A*.

估价函数这里不在多说(其实是我忘了),但提交后TLE...,CODE如下

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <ctime>
using namespace std;
const int MaxHashSize = 1526597;
const int MaxState = 2500000;
int tot,target[256];
char g[9];
int dir[4][2] = {0,1,0,-1,-1,0,1,0};
int getdia[6][4] = {5,5,2,2,3,3,4,4,4,4,0,0,1,1,5,5,2,2,1,1,0,0,3,3};

typedef struct status
{
char  pos;
char  step;
int   g;
char  h;
friend bool operator < (const status& a ,const status& b)
{
if (a.step + a.h < b.step + b.h)
return false;
if (a.step + a.h == b.step + b.h && a.step < b.step)
return false;
return true;
}

};

priority_queue<status> q;

status start;
int Head[MaxHashSize],Next[MaxState];
status st[MaxState];
void init_Hash()
{
memset(Head,-1,sizeof(Head));
}

int GetHashValue(status &x)
{
return x.g % MaxHashSize;
}

bool insert_Hash(int id)
{
int h = GetHashValue(st[id]);
int u = Head[h];
while(u != -1)
{
if (st[u].g == st[id].g)
return false;
u = Next[u];
}
Next[id] = Head[h];
Head[h] = id;
return true;
}

int caculateh(status &x)
{
int res = 0;
int ok = 1;
for(int i = 0 ; i < 9 ; ++ i)
{
int temp = 0;
for(int j = 0 ; j < 3 ; ++ j)
{
int s = (x.g >> (3*i + j)) & 1;
temp |= (s << j);
}
if ( (temp == 0 || temp == 1) && g[i] != 'W')
res ++ ;
else if ( (temp == 2 || temp == 3) && g[i] !='R')
res ++;
else if ( (temp == 4 || temp == 5) && g[i] != 'B')
res ++;
else if (temp == 7 && g[i] != 'E' )
{
res ++;
ok = 0;
}

}
if (ok)
return res;
else
return res - 1;

}

int bfs()
{
int front = 0 ,rear = 1;
q.push(start);
while(!q.empty())
{
status ss = q.top();q.pop();
st[front++] = ss;
if (ss.h == 0)
return ss.step;
if (ss.h + ss.step > 30)
return -1;
int pos = ss.pos;
int x = pos / 3;
int y = pos % 3;
int step = ss.step;
int g = ss.g;
for(int i = 0 ; i < 4 ; ++ i)
{
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if (newx >= 3 || newx < 0 || newy >= 3 || newy < 0)
continue;
int newpos = newx * 3 + newy;
status ns = ss;
int temp = 0;
for(int j = 0 ; j < 3 ; ++ j)
{
int s = (g >> (newpos * 3 + j) )  & 1;
temp |= (s << j);
}
int sis = getdia[temp][i];
for(int j = 0 ; j < 3 ;++ j)
ns.g |= (1 << (newpos*3 + j));
for(int j = 0 ; j < 3 ; ++ j)
if (sis >> j & 1)
ns.g |= (1 << pos * 3 + j);
else
ns.g &= ~(1 << pos * 3 + j);
ns.step = step + 1;
ns.pos = newpos;
ns.h = caculateh(ns);
st[rear] = ns;
if (insert_Hash(rear))
{
q.push(ns);
rear++;
}
}
}
return -1;
}

int main(int argc, char * argv[])
{
int kk = clock();
int s1,s2;
while(scanf("%d%d%*c",&s1,&s2) && s1)
{
tot = 0;
for(int i = 0 ; i < 9 ; ++ i)
scanf("%c%*c",&g[i]);
int fp = (s2-1) * 3 + s1 - 1;
start.pos = fp;
start.g = 0;
init_Hash();
for(int i = 0 ; i < 3 ; ++ i)
start.g |= (1 << (3*fp+i));
st[0] = start;
insert_Hash(0);
start.h = caculateh(start);
start.step = 0;
while(!q.empty())
q.pop();
cout << bfs() << endl;
}
cout << "Time use " << clock() - kk << endl;
return 0;
}


这里的代码中有Clock(),大家可以试试几组数据,30步的极限或者-1,速度非常慢。。(无法忍受)

那么,我们只能改用双广了,因为末状态有256种,所以我们用一个dfs把末状态压进去,提交后AC~

顺便多题一句双广复杂度是 2*n^(a/2) ,而单向的是n^a,code 如下

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int MaxHashSize = 1526597;
const int MaxState = 2500000;
int tot,target[256],ssl;
char g[9];
int dir[4][2] = {0,1,0,-1,-1,0,1,0};
int getdia[6][4] = {5,5,2,2,3,3,4,4,4,4,0,0,1,1,5,5,2,2,1,1,0,0,3,3};

typedef struct status
{
char  pos;
char  step;
int   g;
};

status start;
int Head[MaxHashSize],Next[MaxState];
int Head2[MaxHashSize],Next2[MaxState];
status st[MaxState];
status st2[MaxState];

void init_Hash()
{
memset(Head,-1,sizeof(Head));
memset(Head2,-1,sizeof(Head));
}

int GetHashValue(status &x)
{
return x.g % MaxHashSize;
}

bool insert_Hash(int id ,int l)
{
int h;
if (l == 0)
h = GetHashValue(st[id]);
else
h = GetHashValue(st2[id]);
int u;
if (l == 0)
u = Head[h];
else
u = Head2[h];

while(u != -1)
{
if (l == 0)
{
if (st[u].g == st[id].g)
return false;
u = Next[u];
}
else
{
if (st2[u].g == st2[id].g)
return false;
u = Next2[u];
}
}
if (l == 0)
{
Next[id] = Head[h];
Head[h] = id;
}
else
{
Next2[id] = Head2[h];
Head2[h] = id;
}
return true;
}

int meet(int id,int l)
{
int u,h;
if (l == 0)
{
h = GetHashValue(st[id]);
int u = Head2[h];
while(u != -1)
{
if (st2[u].g == st[id].g)
return st[id].step + st2[u].step;
u = Next2[u];
}

return -1;
}
else
{
h = GetHashValue(st2[id]);
int u = Head[h];
while(u != -1)
{
if (st[u].g == st2[id].g)
return st[u].step + st2[id].step;
u = Next[u];
}

return -1;
}
}

int bfs()
{
int front = 0 ,rear = 1;
int front2 = 0 , rear2 = 256;
while(front < rear && front2 < rear2)
{
if (1)
{
status ss = st[front++] ;
int ans = meet(front-1,0);
if (ans != -1)
return ans > 30 ? -1 : ans;
if (ss.step >= 30)
return -1;
int pos = ss.pos;
int x = pos / 3;
int y = pos % 3;
int step = ss.step;
int g = ss.g;
for(int i = 0 ; i < 4 ; ++ i)
{
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if (newx >= 3 || newx < 0 || newy >= 3 || newy < 0)
continue;
int newpos = newx * 3 + newy;
status ns = ss;
int temp = 0;
for(int j = 0 ; j < 3 ; ++ j)
{
int s = (g >> (newpos * 3 + j) )  & 1;
temp |= (s << j);
}
int sis = getdia[temp][i];
for(int j = 0 ; j < 3 ;++ j)
ns.g |= (1 << (newpos*3 + j));
for(int j = 0 ; j < 3 ; ++ j)
if (sis >> j & 1)
ns.g |= (1 << pos * 3 + j);
else
ns.g &= ~(1 << pos * 3 + j);
ns.step = step + 1;
ns.pos = newpos;
st[rear] = ns;
if (insert_Hash(rear,0))
{
rear++;
}
}
}
status ss = st2[front2++] ;
int ans = meet(front2-1,1);
if (ans != -1)
return ans > 30 ? -1 : ans;
if (ss.step >= 30)
return -1;
int pos = ss.pos;
int x = pos / 3;
int y = pos % 3;
int step = ss.step;
int g = ss.g;
for(int i = 0 ; i < 4 ; ++ i)
{
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if (newx >= 3 || newx < 0 || newy >= 3 || newy < 0)
continue;
int newpos = newx * 3 + newy;
status ns = ss;
int temp = 0;
for(int j = 0 ; j < 3 ; ++ j)
{
int s = (g >> (newpos * 3 + j) )  & 1;
temp |= (s << j);
}
int sis = getdia[temp][i];
for(int j = 0 ; j < 3 ;++ j)
ns.g |= (1 << (newpos*3 + j));
for(int j = 0 ; j < 3 ; ++ j)
if (sis >> j & 1)
ns.g |= (1 << pos * 3 + j);
else
ns.g &= ~(1 << pos * 3 + j);
ns.step = step + 1;
ns.pos = newpos;
st2[rear2] = ns;
if (insert_Hash(rear2,1))
{
rear2++;
}
}
}
return -1;
}

void dfs(int n,int temp)
{
if (n == 9)
{
st2[tot].g = temp;
st2[tot].step = 0;
insert_Hash(tot,1);
st2[tot++].pos = ssl;
}
else
{
int f;
if (g
== 'W')
{
f = temp;
dfs(n+1,f);
f |= (1 << (3*n));
dfs(n+1,f);
}
else if(g
== 'R')
{
f = temp;
f |= (1 << (3*n+1));
dfs(n+1,f);
f |= (1 << 3*n);
dfs(n+1,f);
}
else if(g
== 'B')
{
f = temp;
f |= (1 << 3*n+2);
dfs(n+1,f);
f |= (1 << 3*n);
dfs(n+1,f);
}
else if(g
== 'E')
{
f = temp;
for(int j = 0 ; j < 3 ; ++ j)
f |= (1 << 3*n + j);
dfs(n+1,f);
}
}
}

int main(int argc, char * argv[])
{
int s1,s2;
while(scanf("%d%d%*c",&s1,&s2) && s1)
{
tot = 0;
for(int i = 0 ; i < 9 ; ++ i)
{
scanf("%c%*c",&g[i]);
if (g[i] == 'E')
ssl = i;
}
int fp = (s2-1) * 3 + s1 - 1;
start.pos = fp;
start.g = 0;
init_Hash();
dfs(0,0);
for(int i = 0 ; i < 3 ; ++ i)
start.g |= (1 << (3*fp+i));
st[0] = start;
insert_Hash(0,0);
start.step = 0;
cout << bfs() << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: