【状压DP】poj3254 Corn Fields

题意: 
一块n*m的田,1表示这个地方可以种植,0代表这个地方不能种植。植物种植还必须满足两株植物不能相邻(横竖都不行)。问共有几种种植方法,而且当什么都不种时认为是一种方法。 
解题思路: 
种植用1表示,不种植用0表示。每一行的情况就可以用一个二进制数state来存储。state的范围是 [0 ~ 1<< state). 
dp[i][state]表示第i行状态为state的情况下满足条件的数目。 
状态转移方程为:dp[i][state] += dp[i-1][pre_state];这个state和pre_state必须满足意义所给的条件,即左右不相邻,上下不相邻。那么 第i行状态为state的情况为第i-1行所有满足条件的状态为pre_state相加而成。 
最后的答案为最后一行所有状态的情况和相加而得。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int dp[15][1<<15];
bool is[15][15];
int n,m;
const int MOD = 1e8;

bool check(int x,int state)
{
    if((state&(state<<1))) return false;
    for(int i=1;i<=m;i++)
    {
        if(!is[x][i])
        {
            if(((1<<(m-i))& state)!=0) return false;
        }
    }
    return true;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
          memset(dp,0,sizeof(dp));
          for(int i=1;i<=n;i++) for(int j = 1;j<=m;j++) scanf("%d",&is[i][j]);
          dp[0][0]=1;
          long long ans=0;
          for(int i=1;i<=n;i++)
          {
              for(int j=0;j<(1<<m);j++)
              {
                  if(check(i,j)) 
                  {
                      for(int k=0;k<(1<<m);k++)
                      {
                           if(!(k&j))dp[i][j]+=dp[i-1][k];
                      }
                  }
                  if(i==n)ans=(ans+dp[i][j])%MOD;
              }
          }
         printf("%lld
",ans); 
    }
    return 0;
}
原文地址:https://www.cnblogs.com/rir1715/p/6804756.html