题目大意:农夫约翰有一个M*N的矩形牧场,想在牧场里面种植一些植物,但是这些植物不能够相邻,而且有些地是不能种植的,求共有多少种种植方式。
解题思路:把每一行的状态用二进制的数表示,1表示在该处种植植物,反之,用0表示。根据题意可知:两个相邻的行或者列不能同时为1,且不能种植植物的地方用0表示。用dp[state][i]表示状态为state时,到第i行符合条件的方案数
则状态转移方程为:dp[state][i] =Sigma dp[state'][i-1] (state'为符合条件的所有状态) dp[state][1] =1(state符合条件) OR 0 (state不符合条件)
代码实现如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#define mod 100000000
int M, N, top = 0;
int state[600], num[110];
int dp[20][600];
int cur[20];
bool ok(int x)
{
if(x & x << 1) return 0;
return 1;
}
void init()
{
top = 0;
int total = 1 << N;
for(int i = 0; i < total; i ++)
{
if(ok(i)) state[++top] = i;
}
}
bool fit(int x, int k)
{
if(x & cur[k]) return 0;
return 1;
}
int jcount(int x)
{
int cnt = 0;
while(x)
{
cnt ++;
x = x & (x-1);
}
return cnt;
}
int main()
{
while(~scanf("%d %d", &M, &N))
{
init();
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= M; i ++)
{
cur[i] = 0;
int num;
for(int j = 1; j<= N; j ++)
{
scanf("%d", &num);
if(num == 0)
cur[i] += (1<<(N-j));
}
}
for(int i = 1;i <= top; i ++)
{
if(fit(state[i], 1))
{
dp[1][i] = 1;
}
}
for(int i = 2; i <= M; i ++)
{
for(int k = 1; k <= top; k++)
{
if(!fit(state[k], i)) continue;
for(int j = 1; j <= top; j ++)
{
if(!fit(state[j], i-1)) continue;
if(state[k] & state[j]) continue;
dp[i][k] = (dp[i][k] + dp[i-1][j]) % mod;
}
}
}
int ans = 0;
for(int i = 1; i <= top; i ++)
{
ans = (ans + dp[M][i]) % mod;
}
printf("%d\n", ans);
}
}