zoukankan      html  css  js  c++  java
  • 动态规划-状态压缩-覆盖

    2020-03-01 23:08:51

    问题描述:

    你有一块棋盘,棋盘上有一些格子已经坏掉了。你还有无穷块大小为1 * 2的多米诺骨牌,你想把这些骨牌不重叠地覆盖在完好的格子上,请找出你最多能在棋盘上放多少块骨牌?这些骨牌可以横着或者竖着放。

    输入:n, m代表棋盘的大小;broken是一个b * 2的二维数组,其中每个元素代表棋盘上每一个坏掉的格子的位置。

    输出:一个整数,代表最多能在棋盘上放的骨牌数。

    示例 1:

    输入:n = 2, m = 3, broken = [[1, 0], [1, 1]]
    输出:2
    解释:我们最多可以放两块骨牌:[[0, 0], [0, 1]]以及[[0, 2], [1, 2]]。

    示例 2:

    输入:n = 3, m = 3, broken = []
    输出:4
    解释:下图是其中一种可行的摆放方式

    限制:

    1 <= n <= 8
    1 <= m <= 8
    0 <= b <= n * m

    问题求解:

    最难考虑到的就是我们优先放置竖排,最后放置横排即可遍历当前行的所有可行解。

        public int domino(int m, int n, int[][] broken) {
            int[][] dp = new int[m + 1][1 << n];
            int[][] board = new int[m][n];
            for (int[] b : broken) board[b[0]][b[1]] = 1;
            int[] states = new int[m + 1];
            states[0] = (1 << n) - 1;
            for (int i = 1; i <= m; i++) {
                int state = 0;
                for (int j = 0; j < n; j++) {
                    if (board[i - 1][j] == 1) state |= (1 << (n - 1 - j));
                }
                states[i] = state;
            }
            for (int i = 1; i <= m; i++) {
                for (int u = 0; u < 1 << n; u++) {
                    if ((u & states[i - 1]) != 0) continue;
                    int prev = u | states[i - 1];
                    for (int v = 0; v < 1 << n; v++) {
                        if ((v & states[i]) != 0) continue;
                        // 枚举竖放的位置
                        for (int k = v;; k = (k - 1) & v) {
                            if ((k & prev) == 0) {
                                dp[i][v] = Math.max(dp[i][v], calc_1(k) + calc_2(v ^ k) + dp[i - 1][u]);
                            }
                            if (k == 0) break;
                        }
                    }
                }
            }
            int res = 0;
            for (int i = 0; i < 1 << n; i++) res = Math.max(res, dp[m][i]);
            return res;
        }
        
        private int calc_1(int num) {
            int res = 0;
            for (int i = 0; i < 32; i++) if ((num & (1 << i)) != 0) res += 1;
            return res;
        }
        
        private int calc_2(int num) {
            int res = 0;
            for (int i = 0; i < 32;) {
                if ((num & (1 << i)) != 0 && i + 1 < 32 && (num & (1 << (i + 1))) != 0) {
                    res += 1;
                    i += 2;
                }
                else {
                    i += 1;
                }
            }
            return res;
        }

    本题的最优解是使用二分图匹配匈牙利算法求解,待更新。

  • 相关阅读:
    php5使用docker工具安装mcrypt
    golang 三目运算的实现
    图片壁纸
    使用golang实现栈(stack)
    Qt 异常处理 QT_TRY和QT_CATCH
    OpenCV 实现图片HDR功能
    OpenCV HDR合成
    OpenCV .直方图均衡 CLAHE算法学习
    OpenCV 直方图均衡化原理
    OpenCV 直方图绘制以及直方图均衡化
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/12392898.html
Copyright © 2011-2022 走看看