POJ 1038 Bugs Integrated, Inc.(DFS + 三进制状压 + 滚动数组 思维)题解

题意:n*m方格,有些格子有黑点,问你最多裁处几张2 * 3(3 * 2)的无黑点格子。

思路:我们放置2 * 3格子时可以把状态压缩到三进制:

关于状压:POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划),写的很详细

所以我们直接枚举每一行的所有可能状态,并算出每种状态最大值。这样我们到最后只要找到n行所有状态最大值就行了。

代码:

#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 150 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
int dp[2][60000], ter[15];
int vis[160][15];
int t, n, m, k;
int now[15], pre[15];
void getNow(int i){
    for(int k = 1; k <= m; k++){
        if(vis[i][k]){
            now[k] = 2;
        }
        else{
            if(pre[k] <= 1) now[k] = 0;
            else now[k] = 1;
        }
    }
}
int getSt(){
    int ret = 0;
    for(int k = 1; k <= m; k++){
        ret = ret * 3 + now[k];
    }
    return ret;
}
void dfs(int i, int j, int num){
    int nowSt;

    if(j > m){
        nowSt = getSt();
        dp[i % 2][nowSt] = max(dp[i % 2][nowSt], num);
        return;
    }

    // ▇ ▇ ▇
    // ▇ ▇ ▇
    if(j >= 3 && !now[j - 2] && !now[j - 1] && !now[j]){
        now[j - 2] = now[j - 1] = now[j] = 2;
        nowSt = getSt();
        dp[i % 2][nowSt] = max(dp[i % 2][nowSt], num + 1);
        dfs(i, j + 2, num + 1);
        now[j - 2] = now[j - 1] = now[j] = 0;
    }

    // ▇ ▇
    // ▇ ▇
    // ▇ ▇
    if(j >= 2 && !now[j - 1] && !now[j] && !pre[j - 1] && !pre[j]){
        now[j - 1] = now[j] = 2;
        nowSt = getSt();
        dp[i % 2][nowSt] = max(dp[i % 2][nowSt], num + 1);
        dfs(i, j + 2, num + 1);
        now[j - 1] = now[j] = 0;
    }

    nowSt = getSt();
    dp[i % 2][nowSt] = max(dp[i % 2][nowSt], num);
    dfs(i, j + 1, num);
}
int main(){
    ter[0] = 1;
    for(int i = 1; i <= 12; i++){
        ter[i] = ter[i - 1] * 3;
    }
    scanf("%d", &t);
    while(t--){
        scanf("%d%d%d", &n, &m, &k);
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= k; i++){
            int x, y;
            scanf("%d%d", &x, &y);
            vis[x][y] = 1;
        }

        //0 都可以,1 上一行不可以,2 都不可以
        int temp = 0;
        for(int i = 1; i <= m; i++) temp = temp * 3 + 2;
        memset(dp[0], -1, sizeof(dp[0]));
        dp[0][temp] = 0;
        for(int i = 1; i <= n; i++){
            memset(dp[i % 2], -1, sizeof(dp[0]));
            for(int st = 0; st < ter[m]; st++){
                if(dp[(i + 1) % 2][st] == -1) continue;
                int tmp = st;
                for(int j = m; j >= 1; j--){
                    pre[j] = tmp % 3;
                    tmp /= 3;
                }
                getNow(i);
                dfs(i, 1, dp[(i + 1) % 2][st]);
            }
        }

        int Max = -1;
        for(int i = 0; i < ter[m]; i++)
            Max = max(Max, dp[n % 2][i]);
        printf("%d
", Max);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/10659856.html