HDU Puzzle 3278

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;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值