洛谷P1879-玉米田(状压dp)

题意:洛谷P1879

这道题目可以说是炮兵阵地和互不侵犯的合成简化版,给定一个 N ∗ M N*M NM的图, 1 1 1表示可以种玉米, 0 0 0表示不可以种玉米,若选择 1 1 1个格子种下玉米,那么这个格子的上下左右格子不能再种玉米,问有多少种种玉米的方案。

分析:

先将读入的图转为二进制数,此时的二进制数中 1 1 1表示不能种玉米, 0 0 0表示能种玉米。然后预处理一行内所有可行的种玉米状态,再预处理第一行所有可行状态的方案数(即为1)。从第二行开始向下状态转移即可,最终答案就是最后一行的所有状态的方案数之和。状态转移方程:
d p [ i ] [ j ] + = d p [ i − 1 ] [ k ] dp[i][j]+=dp[i-1][k] dp[i][j]+=dp[i1][k] i i i表示当前行, j j j表示当前行状态, k k k表示上一行状态。
值得注意的是状态转移的时候要判断 j 、 k j、k jk的状态合法性。

A C AC AC代码 1 1 1

#include 
using namespace std;
typedef long long ll;

const int maxn = 500 + 5;
const ll  mod  = 100000000;

int n, m, x, cnt, maxsta, sta[maxn], num[maxn], pic[15];
ll ans, dp[15][maxn];

int main(){
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			scanf("%d", &x);
			if(x == 0) pic[i] += (1 << (j - 1));
		}
	}
	maxsta = 1 << m;
	for(int i = 0; i < maxsta; i++) if(!(i & (i << 1)) && !(i & (i >> 1))){
		sta[++cnt] = i;
	}
	for(int i = 1; i <= cnt; i++) if(!(sta[i] & pic[1])){
		dp[1][i] = 1;
	}
	for(int i = 2; i <= n; i++){
		for(int j = 1; j <= cnt; j++){
			if(sta[j] & pic[i]) continue;//当前行状态不能和当前行的图有冲突
			for(int k = 1; k <= cnt; k++){
				if(sta[k] & pic[i - 1] || sta[k] & sta[j]) continue;//上一行状态不能和上一行图有冲突,也不能和当前行状态有冲突
				dp[i][j] = (dp[i][j] % mod + dp[i - 1][k] % mod) % mod;
			}
		}
	}
	for(int i = 1; i <= cnt; i++) ans = (ans % mod + dp[n][i] % mod) % mod;
	printf("%lld\n", ans);
    return 0; 
}

刚开始瞎写的三维状压 d p dp dp也过了。
A C AC AC代码 2 2 2

#include 
using namespace std;
typedef long long ll;

const int maxn = 500 + 5;
const ll  mod  = 100000000;

int n, m, x, cnt, maxsta, sta[maxn], num[maxn], pic[15];
ll ans, dp[15][maxn][maxn];

int main(){
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &x);
            if(x == 0) pic[i] += (1 << (j - 1));
        }
    }
    maxsta = 1 << m;
    for(int i = 0; i < maxsta; i++) if(!(i & (i << 1)) && !(i & (i >> 1))){
        sta[++cnt] = i;
    }
    for(int i = 1; i <= cnt; i++) if(!(sta[i] & pic[1])){
        dp[1][i][1] = 1;
    }
    for(int i = 2; i <= n; i++){
        for(int j = 1; j <= cnt; j++){
            if(sta[j] & pic[i]) continue;
            for(int k = 1; k <= cnt; k++){
                if(sta[k] & pic[i - 1] || sta[j] & sta[k]) continue;
                for(int l = 1; l <= cnt; l++){
                    if(sta[l] & pic[i - 2] || sta[l] & sta[k]) continue;
                    dp[i][j][k] = (dp[i][j][k] % mod + dp[i - 1][k][l] % mod) % mod;
                }
            }
        }
    }
    for(int i = 1; i <= cnt; i++){
        for(int j = 1; j <= cnt; j++){
            ans = (ans % mod + dp[n][i][j] % mod) % mod;
        }
    }
    printf("%lld\n", ans);
    return 0; 
}

你可能感兴趣的:(dp)