poj3254
一道状态压DP题目。将每一行进行编码,1表示种0表示不种。首先求解出每一行合法的状态集合。对于第i行状态j,如果j&(j<<1)==0并且对于该行为0的地方j在当前位的二进制也是0,则表明状态j合法。用dp[i][j]表示第i行状态为j时(j合法的)的方法数,得到状态转移方程如下:
dp[i][j]=sum(dp[i-1][k]) j&k==0 ;在计算dp[i][j]时,可以枚举上一行的所有状态。
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<vector>
using namespace std;
int const SIZE = 13;
typedef long long LL;
const int mod = 100000000;
vector<int> vec[SIZE]; //保存第i行合法状态
int a[SIZE][SIZE];
LL dp[SIZE][1 << 13];
int bit[SIZE];
int m, n;
int main(){
int i, j,k;
bit[0] = 1;
for (i = 1; i < SIZE; i++)
bit[i] = bit[i - 1] * 2;
while (~scanf("%d%d", &n, &m)){
for (i = 1; i <= n;i++)
for (j = 1; j <= m; j++)
scanf("%d", &a[i][j]);
for (i = 0; i <= n; i++)
vec[i].clear(); //初始化清空
//计算每一行合法状态并保留在vec中
vec[0].push_back(0);
for (i = 1; i <= n; i++){
for (j = 0; j < bit[m]; j++){
if ((j&(j << 1)))
continue;
for (k = 1; k <= m; k++){
if ((a[i][k] == 0) && (bit[k - 1] & j)!= 0)
break;
}
if (k == m + 1)
vec[i].push_back(j);
}
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;//0块土地时候什么也不种,也是一种方法
for (i = 1; i <= n; i++){
for (j = 0; j < (int)vec[i].size(); j++){
for (k = 0; k < (int)vec[i - 1].size(); k++){
if (!(vec[i - 1][k] & vec[i][j])){ //状态相容
dp[i][j] += dp[i - 1][k];
dp[i][j] %= mod;
}
}
}
}
LL ans = 0;
for (i = 0; i < (int)vec[n].size(); i++){
ans += dp[n][i];
ans %= mod;
}
printf("%I64d\n", ans);
}
return 0;
}

浙公网安备 33010602011771号