hdu4531 乾坤大挪移

题意:中文题目(略)

分析:其实就是一个暴力的bfs, 关键是模拟移动,判连通,以及状态的表示。

每个格子移动过程中,内部四个小三角的相对顺序是不变的,也就是移动过程中,格子是作为一个整体在移动的,,小三角只是在判连通时才用到,所以状态的表示可以将每个格子作为一个整体,这样的话,总共就是9个格子,用0~8表示,这样是否很熟悉了? 可以用类似八数码的哈希方法,用康托展开将每一个状态hash到一个整数上,剩下的就是模拟了。

很惭愧,单是敲这个代码就用了快俩个小时……

hdu4531
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<vector>

using namespace std;

const int N = 3;
const int M = 362880 + 10;
struct Grid
{
    int a[4];
}p[10];//保存初始时的9 个格子

char str[10];
int g[N][N];//记录移动过程中的地图,只记录对应格子的下标 0 ~ 8
bool row[N], col[N];//记录该行或该列能否移动
int a[N * N];//保存g对应的序列
int cantor[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
bool vis[M];

int dir[4][3][3] = { {{-1,0,1}, {0,0,2}, {0,0,3}}, {{0,0,1}, {0,0,2}, {1,0,-1}}, {{0,0,-1}, {0,0,-2}, {0,-1,1}}, {{0,0,-3}, {0,0,-2}, {0,1,-1}}};
//判连通是用到的, 预处理一下,方便找出每个小格子相邻的格子

struct node
{
    int state, step;
    node(){}
    node(int s, int st):state(s), step(st){}
};

void printMat()
{
    for(int i = 0; i < N; ++i)
    {
        for(int j = 0; j < N; ++j)
            cout << g[i][j] << ' ' ;
        cout << endl;
    }
}

void gToA()//将g保存在数组a
{
    int t = 0;
    for(int i = 0; i < N; ++i)
        for(int j = 0; j < N; ++j)
            a[t++] = g[i][j];
}

void aToG()//将数组a转化为矩阵
{
    int t = 0;
    for(int i = 0; i < N; ++i)
        for(int j = 0; j < N; ++j)
            g[i][j] = a[t++];
}

int pack()//利用康托展开哈希
{
    int ans = 0;

    gToA();

    for(int i = 0; i < 9; ++i)
    {
        int t = 0;
        for(int j = i + 1; j < 9; ++j)
            if(a[j] < a[i]) ++t;
        ans += t * cantor[8 - i];
    }

    return ans;
}

void unpack(int s)//将状态还原
{
    char p[10] = {0};

    for(int i = 0; i < 9; ++i)
    {
        int t = s / cantor[8 - i], j;
        for(j = 0; j < 9; ++j)
            if(!p[j])
            {
                if(t == 0) break;
                --t;
            }
        a[i] = j;
        p[j] = 1;
        s %= cantor[8 - i];
    }

    aToG();
    return ;
}

bool mark[N][N][4];//标记每个格子上的小三角

void dfs(int i, int j, int m, int color)
{
    mark[i][j][m] = true;
    for(int k = 0; k < 3; ++k)
    {
        int xi = i + dir[m][k][0], yi = j + dir[m][k][1], t = m + dir[m][k][2];
        if( xi < 0 || xi >= N || yi < 0 || yi >= N || p[g[xi][yi]].a[t] != color) continue;
        if(mark[xi][yi][t]) continue;
        dfs(xi, yi, t, color);
    }
}
bool check()//判断是否连通
{
    bool colorV[4] = {0};
    memset(mark, false, sizeof(mark));
    for(int i = 0; i < N; ++i)
        for(int j = 0; j < N; ++j)
        {
            for(int m = 0; m < 4; ++m)
            {
                if(mark[i][j][m]) continue;
                int color = p[g[i][j]].a[m];
                if(colorV[color]) return false;//若同一个颜色存在俩个连通分量,则不符合
                colorV[color] = true;
                dfs(i, j, m, color);
            }
        }
    return true;
}

void shitRowL(int r)
{
    int tmp = g[r][0];
    g[r][0] = g[r][1];
    g[r][1] = g[r][2];
    g[r][2] = tmp;
}

void shitRowR(int r)
{
    int tmp = g[r][2];
    g[r][2] = g[r][1];
    g[r][1] = g[r][0];
    g[r][0] = tmp;
}

void shitColU(int c)
{
    int tmp = g[0][c];
    g[0][c] = g[1][c];
    g[1][c] = g[2][c];
    g[2][c] = tmp;
}

void shitColD(int c)
{
    int tmp = g[2][c];
    g[2][c] = g[1][c];
    g[1][c] = g[0][c];
    g[0][c] = tmp;
}

queue<node> Q;

void addNode(int s, int st)
{
    if(!vis[s]) {
        Q.push(node(s, st));
        vis[s] = true;
    }
}

int BFS(int s)
{
    memset(vis,false,sizeof(vis));
    vis[s] = true;
    while(!Q.empty())
        Q.pop();
    Q.push(node(s, 0));

    while(!Q.empty())
    {
        node cur = Q.front();
        Q.pop();
        unpack(cur.state);
        //printMat();
        if(check())
            return cur.step;
        for(int i = 0; i < 3; ++i)
        {
            if(row[i])
            {
                shitRowL(i);
                int s = pack();
                shitRowR(i);
                addNode(s, cur.step + 1);

                shitRowR(i);
                s = pack();
                shitRowL(i);
                addNode(s, cur.step + 1);
            }

            if(col[i])
            {

                shitColD(i);
                s = pack();
                shitColU(i);
                addNode(s, cur.step + 1);

                shitColU(i);
                s = pack();
                shitColD(i);
                addNode(s, cur.step + 1);
            }
        }    
    }
    return -1;
}
int main()
{
    int T, cas = 0;
    scanf("%d",&T);
    while(T--)
    {
        int t = 0;

        for(int i = 0; i < N; ++i)
        {
            row[i] = col[i] = true;
            for(int j = 0;j < N; ++j)
            {
                scanf("%s",str);
                for(int k = 0; k < 4; ++k)
                {
                    if(str[k] == 'R')
                        p[t].a[k] = 0;
                    else if(str[k] == 'G')
                        p[t].a[k] = 1;
                    else if(str[k] == 'B')
                        p[t].a[k] = 2;
                    else p[t].a[k] = 3;
                }
                g[i][j] = t++;
                if(str[4] == '1') 
                    col[j] = row[i] = false;
            }
        }
        printf("Case #%d: %d\n", ++cas, BFS(0));
    }
    return 0;
}

 

posted @ 2013-04-07 02:07  枕边梦  阅读(247)  评论(0编辑  收藏  举报