一道状态压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; }
时间: 2024-11-06 03:54:06