zoukankan      html  css  js  c++  java
  • HDU-4531 吉哥系列故事——乾坤大挪移 模拟

    题意:给定一个九宫格,然后能够选择某行或者是某列滚动,每个小方格分为上下左右四个块,每个块可以涂上4种不同的颜色。问最少使用多少步能够使得所有相同颜色相互联通。

    分析:由于九宫格的所有的状态只有9!(362880)种,于是想起了先对每个格子进行标号,然后根据逆序对的数量进行一个递增进制数的hash处理,这样bfs搜索就能够去重了,接着只需要判断每个状态是否满足联通即可。这里的判定选择了先统计了不同颜色格子的数量然后dfs搜索,应该并查集也可以搞。滚动使用指针滚动即可,对于不能动的格子该格子所在行和列都不能够滚动。

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    // 9! = 362880
    const int LIM = 362880;
    int fac[9]; // 递增进制数的权值 
    int tot[4]; // 四种颜色的个数 
    char vis[LIM]; // hash九宫格 
    char op[6]; // 滚动的操作的限制 
    char hav[50]; // 4*9个格子的标记 
    
    struct Block {
        char color[6];
        int id;
    }bk[3][3];
    
    struct Node {
        Block *ptr[3][3];
        int key;
        int ti;
        Node() {}
        Node(Block (*x)[3]) {
            ti = 0;
            for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
                    ptr[i][j] = &x[i][j]; 
                }
            }
            getkey();
        }
        void show() {
            for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
                    printf("%5d", ptr[i][j]->id);
                }
                puts("");
            }
            puts("");
        }
        void getkey() {
            int cnt;
            key = 0;
            for (int i = 0; i < 8; ++i) {
                cnt = 0;
                for (int j = i+1; j < 9; ++j) {
                    if (ptr[j/3][j%3]->id < ptr[i/3][i%3]->id) ++cnt;
                }
                key += cnt * fac[8-i];
            }
        }
        int dfs(int x, int y, int z) {
            if (hav[(x*3+y)*4+z]) return 0;
            hav[(x*3+y)*4+z] = 1;
            char ch = ptr[x][y]->color[z];
            int ret = 1;
            if (z == 0) {
                if (ptr[x][y]->color[2] == ch) ret += dfs(x, y, 2);
                if (ptr[x][y]->color[3] == ch) ret += dfs(x, y, 3);
                if (x > 0 && ptr[x-1][y]->color[1] == ch) ret += dfs(x-1, y, 1);
            } else if (z == 1) {
                if (ptr[x][y]->color[2] == ch) ret += dfs(x, y, 2);
                if (ptr[x][y]->color[3] == ch) ret += dfs(x, y, 3);
                if (x < 2 && ptr[x+1][y]->color[0] == ch) ret += dfs(x+1, y, 0);
            } else if (z == 2) {
                if (ptr[x][y]->color[0] == ch) ret += dfs(x, y, 0);
                if (ptr[x][y]->color[1] == ch) ret += dfs(x, y, 1);
                if (y > 0 && ptr[x][y-1]->color[3] == ch) ret += dfs(x, y-1, 3);
            } else {
                if (ptr[x][y]->color[0] == ch) ret += dfs(x, y, 0);
                if (ptr[x][y]->color[1] == ch) ret += dfs(x, y, 1);
                if (y < 2 && ptr[x][y+1]->color[2] == ch) ret += dfs(x, y+1, 2);
            }
            return ret;
        }
        bool judge() {
            memset(hav, 0, sizeof (hav));
            for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
                    for (int k = 0; k < 4; ++k) {
                        if (!hav[(i*3+j)*4+k]) {
                            int cnt = dfs(i, j, k);
                            switch(ptr[i][j]->color[k]) {
                                case 'R': if (cnt != tot[0]) return false; break;
                                case 'G': if (cnt != tot[1]) return false; break;
                                case 'B': if (cnt != tot[2]) return false; break;
                                default : if (cnt != tot[3]) return false;
                            }
                        }
                    }
                }
            }
            return true;
        }
    };
    
    void pre() {
        fac[1] = 1;
        for (int i = 2; i < 9; ++i) {
            fac[i] = fac[i-1] * i;
        }
    }
    
    void swapr(Block *x[], Block *y[], int dir) { // 横向的滚动
        if (dir == 0) { // 向左
            y[0] = x[1], y[1] = x[2], y[2] = x[0];
        } else { // 向右
            y[0] = x[2], y[1] = x[0], y[2] = x[1];
        }
    }
    
    void swapc(Block *x[], Block *y[], int dir) { // 纵向的滚动
        if (dir == 0) { // 向上 
            y[0] = x[3], y[3] = x[6], y[6] = x[0];
        } else { // 向下 
            y[0] = x[6], y[3] = x[0], y[6] = x[3];
        }
    }
    
    int bfs() {
        queue<Node>q;
        Node tmp = Node(bk);
        Node pos;
        memset(vis, 0, sizeof (vis));
        q.push(tmp); // 初始化是没有逆序对的
        vis[tmp.key] = 1;
        while (!q.empty()) {
            pos = q.front();
            q.pop();
            if (pos.judge()) {
                return pos.ti;
            }
            for (int i = 0; i < 6; ++i) {
                if (op[i]) continue;
                tmp = pos;
                if (i < 3) { // 横向的滚动 
                    for (int j = 0; j < 2; ++j) {
                        swapr(&pos.ptr[i][0], &tmp.ptr[i][0], j);
                        tmp.getkey();
                        tmp.ti = pos.ti + 1;
                        if (!vis[tmp.key]) {
                            vis[tmp.key] = 1;
                            q.push(tmp);
                        }
                    }
                } else { // 纵向的 
                    for (int j = 0; j < 2; ++j) {
                        swapc(&pos.ptr[0][i%3], &tmp.ptr[0][i%3], j);
                        tmp.getkey();
                        tmp.ti = pos.ti + 1;
                        if (!vis[tmp.key]) {
                            vis[tmp.key] = 1;
                            q.push(tmp);
                        }
                    }
                }
            }
        }
    }
    
    int main() {
        int T, ca = 0;
        pre();
        scanf("%d", &T);
        while (T--) {
            memset(op, 0, sizeof (op));
            memset(tot, 0, sizeof (tot));
            for (int i = 0; i < 3; ++i) {
                for (int j = 0; j < 3; ++j) {
                    scanf("%s", bk[i][j].color);
                    for (int k = 0; k < 4; ++k) {
                        switch(bk[i][j].color[k]) {
                            case 'R': ++tot[0]; break;
                            case 'G': ++tot[1]; break;
                            case 'B': ++tot[2]; break;
                            default : ++tot[3];
                        }
                    }
                    bk[i][j].id = i*3+j; // 0-8
                    if (bk[i][j].color[4] == '1') {
                        op[i] = op[3+j] = 1; // 两种操作无法进行
                    }
                }
            }
            printf("Case #%d: %d
    ", ++ca, bfs());
        }
        return 0;
    }
  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/Lyush/p/3416507.html
Copyright © 2011-2022 走看看