题目链接:http://poj.org/problem?id=3254
题目大意:给一个m*n的牧场,要在上面种谷物,要求相邻两块地不能同时种谷物,并且牧场本身就有若干块土地是不能种谷物的,问共有多少种发法。(什么也不种算一种)
类型:状压dp
思路:不考虑土地的问题,先枚举出所有满足条件的种法,存在一个数组中,然后在读入土地的时候,将每行土地的状态取反后构成一个状态,这样,将土地状态和已经计算出的状态按位与,为0该状态就可取
状态转移方程:dp[i][j]+=sum(dp[i-1][k]) k=0,1,2...其中dp[i-1][k]要为满足上述条件的可取状态。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int mod=1e8;
const int M=500;
int map[15];
int per[M];
int dp[15][M];
int main()
{
int n,m;
while(~scanf("%d%d",&m,&n))
{
memset(map,0,sizeof(map));
memset(dp,0,sizeof(dp));
memset(per,0,sizeof(per));
int k=0;
for(int i=0;i<(1<<n);i++)
{
if((i&(i<<1))==0)
per[k++]=i;
}
for(int i=1;i<=m;i++)
{
for(int j=0;j<n;j++)
{
int x;
scanf("%d",&x);
if(x==0)
map[i]=(map[i]|(1<<j) );
}
}
// for(int i=0;i<k;i++)
// if(!(per[i]&map[1]))
// dp[1][i]=1;
for(int i=1;i<=m;i++)
{
for(int j=0;j<k;j++)
{
if(i==1)
{
if((map[i]&per[j])==0)
dp[i][j]=1;
continue;
}
if(dp[i-1][j]==0)
continue;
// if(map[i-1]&per[j])
// continue;
for(int p=0;p<k;p++)
{
if(per[p]&map[i])
continue;
if(per[p]&per[j])
continue;
dp[i][p]=(dp[i][p]+dp[i-1][j])%mod;
}
}
}
int ans=0;
for(int i=0;i<k;i++)
ans=(ans+dp[m][i])%mod;
printf("%d\n",ans);
}
return 0;
}