http://acm.hdu.edu.cn/showproblem.php?pid=3278
题意很简单, 给一个4X6的矩形,其中又white ,blank , grey 三种颜色各有8个格子 ,给定一个初始状态,求用最少的操作次数将图形变化为中间的8个格子颜色相同。
分析:一开始想到了IDA* , 但是这题IDA* 是不行的, 原因我也不知道是为什么。 因为用三种颜色,在状态压缩的时候3^24显然会超内存,但是2^24不会超,这里用了一个很巧妙的预处理:从最终的状态开始考虑,即中间的8个格子都是一种颜色,这时旁边的两种颜色都可以看作一种颜色,因为它们对中间的颜色来说都是无关的,因此就可以将状态压缩到2^24,2kw。 预处理从最终的状态能到达的状态,并记录下step , 因为有2Kw个状态,直接用int存step会超内存, 这里用char来代替int数组使用。。 最后1500ms水过。。
代码:
/*
HDU 3278 Puzzle
Tips : 预处理 + search
runtime : 1578ms
Memory : 17908K
*/
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<bitset>
#include<queue>
#define MAX 17000000
using namespace std;
struct Node{
int maze[4][6] ;
int ZIP(){
int res = 0 ;
for(int i=0;i<4;i++){
for(int j=0;j<6;j++){
res <<= 1 ;
res += maze[i][j] ;
}
}
return res;
}
void rezip(int res){
for(int i=3;i>=0;i--){
for(int j=5;j>=0;j--){
maze[i][j] = res&1 ;
res >>= 1 ;
}
}
}
}s,t;
queue<int> que ;
char step[MAX] ; //用char数组来代替int数组计数
void l_move(int i){
for(int ii=0;ii<4;ii++){
if(ii != i){
for(int j=0;j<6;j++){
t.maze[ii][j] = s.maze[ii][j] ;
}
}
else{
for(int j=0;j<5;j++){
t.maze[ii][j] = s.maze[ii][j+1] ;
}
t.maze[ii][5] = s.maze[ii][0] ;
}
}
}
void r_move(int i){
for(int ii=0;ii<4;ii++){
if(ii != i){
for(int j=0;j<6;j++){
t.maze[ii][j] = s.maze[ii][j] ;
}
}
else{
for(int j=5;j>0;j--){
t.maze[ii][j] = s.maze[ii][j-1] ;
}
t.maze[ii][0] = s.maze[ii][5] ;
}
}
}
void u_move(int j){
for(int jj=0;jj<6;jj++){
if(jj == j){
for(int i=0;i<3;i++){
t.maze[i][jj] = s.maze[i+1][jj] ;
}
t.maze[3][jj] = s.maze[0][jj] ;
}
else{
for(int i=0;i<4;i++){
t.maze[i][jj] = s.maze[i][jj] ;
}
}
}
}
void d_move(int j){
for(int jj=0;jj<6;jj++){
if( jj == j){
for(int i=3;i>0;i--){
t.maze[i][jj] = s.maze[i-1][jj] ;
}
t.maze[0][jj] = s.maze[3][jj] ;
}
else{
for(int i=0;i<4;i++){
t.maze[i][jj] = s.maze[i][jj] ;
}
}
}
}
void bfs(){
memset(s.maze,0,sizeof(s.maze));
memset(t.maze,0,sizeof(t.maze));
int szip ;
for(int i=1;i<=2;i++){
for(int j=1;j<=4;j++){
s.maze[i][j] = 1;
t.maze[i][j] = 1 ;
}
}
int nzip = s.ZIP() ;
memset(step,-1,sizeof(step));
step[nzip] = 0 ;
while(!que.empty()) que.pop() ;
que.push(nzip) ;
while(!que.empty()){
nzip = que.front() ; que.pop() ;
s.rezip(nzip);
for(int i=0;i<4;i++){ //水平移动一个单位
r_move(i) ; szip = t.ZIP() ;
if(step[szip] == -1){
step[szip] = step[nzip] + 1 ;
que.push(szip) ;
}
l_move(i); szip = t.ZIP();
if(step[szip] == -1){
step[szip] = step[nzip] + 1 ;
que.push(szip);
}
}
for(int i=0;i<6;i++){ //竖直移动一个单位
u_move(i) ; szip = t.ZIP() ;
if(step[szip] == -1){
step[szip] = step[nzip] + 1;
que.push(szip) ;
}
d_move(i) ; szip = t.ZIP() ;
if(step[szip] == -1){
step[szip] = step[nzip] + 1;
que.push(szip) ;
}
}
}
}
void C_clo(int col){
for(int i=0;i<4;i++){
for(int j=0;j<6;j++){
if(s.maze[i][j] == col)
t.maze[i][j] = 1 ;
else
t.maze[i][j] = 0 ;
}
}
}
int main(){
//freopen("1in","r",stdin);
//freopen("1out","w",stdout);
int T,res;
bfs(); //预处理
char map[6] ;
scanf("%d",&T);
for(int ncase = 1; ncase <= T ; ncase ++ ){
printf("Case %d: ",ncase);
for(int i=0;i<4;i++){
scanf("%s",map);
for(int j=0;j<6;j++){
if(map[j] == 'W') s.maze[i][j] = 0 ;
if(map[j] == 'B') s.maze[i][j] = 1 ;
if(map[j] == 'G') s.maze[i][j] = 2 ;
}
}
res = 100000000 ;
for(int i=0;i<3;i++){
C_clo(i) ;
int nzip = t.ZIP() ;
if(res > step[nzip])
res = step[nzip] ;
}
printf("%d\n",res);
}
return 0;
}