LCP 4. 覆盖 状压DP

OJ

题意已经非常清楚了,这题其实跟[POJ 2411]这道题类似,算是一个加强版,都是放置多米诺骨牌,不过这个题添加了障碍物,也就是多加了判断而已,不过也在放置逻辑上加大了难度。

核心思想依然是:枚举上一行的状态,搜索这一行所有可能的填写情况。
我们定义如下这种填充表示方式:如果一个骨牌是横着放的,那么它所在的两个方格都填充1.如果它是竖着放的,那么它所在的两个格子中,上面的那个填0,下面的这个填1.如下图所示:

代码实现

int[][] dp;
boolean[][] no;

// 根据之前一行的状态来搜索当前行的最大放置方式
void dfs(int preSta, int curSta, int row, int col, int m, int now) {
    if (col == m) {
    	// 如果不是第一行
        if (row != 0) {
            dp[row][curSta] = Math.max(dp[row][curSta], now + dp[row - 1][preSta]);
        } else {
            dp[row][curSta] = Math.max(dp[row][curSta], now);
        }
        return;
    }
    // 如果当前位置有障碍物
    if (no[row][col]) {
        dfs(preSta, curSta | (1 << col), row, col + 1, m, now);
    } else {
    	// 横着放置
        if (col + 2 <= m && !no[row][col + 1]) {
            int tmp = curSta | (1 << col);
            tmp = tmp | (1 << (col + 1));
            dfs(preSta, tmp, row, col + 2, m, now + 1);
        }
        // 竖着放置,能放置的前提是前一行留有空位
        if (row != 0 && ((preSta >> col) & 1) != 1) {
            dfs(preSta, curSta | (1 << col), row, col + 1, m, now + 1);
        } else {
            dfs(preSta, curSta, row, col + 1, m, now);
        }
    }
}

public int domino(int n, int m, int[][] broken) {
    dp = new int[n][(1 << m)];
    no = new boolean[n][m];
    for (int[] tmp : broken) {
        no[tmp[0]][tmp[1]] = true;
    }
    for (int i = 0; i < n; ++i) {
        Arrays.fill(dp[i], Integer.MIN_VALUE);
    }
    dp[0][(1 << m) - 1] = 0;
    for (int i = 0; i < n; ++i) {
        for (int preSta = 0; preSta < (1 << m); ++preSta) {
            dfs(preSta, 0, i, 0, m, 0);
        }
    }
    int ans = Integer.MIN_VALUE;
    for (int i = 0; i < (1 << m); ++i) {
        ans = Math.max(dp[n][i], ans);
    }
    return ans;
}
发布了180 篇原创文章 · 获赞 49 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/P19777/article/details/104244289