題意:一農民有一片N*M的地,地裏的土地有的肥沃有的不肥沃,0表示不肥沃,1相反。農民需要往這片地裏放養牛,一隻牛只能在一塊1*1的地裏且只在肥沃的地裏。牛的數量不限,問這片地裏能有多少种放牛的情況。
思路:首先能確定這是一道dp題,爲了簡化dp的狀態存儲,使用了狀態壓縮,我們可以用一個二進制數來表示一行中土地是否肥沃的情況或者表示一行裏能放牛的所有情況,題中說明一行最多12個地那麼我們用一個12位的二進制數就可以表示土地和放牛的情況了,例如1表示有牛0是沒有。首先我們在輸入的時候將n*m的土地情況轉化成n個數來表示n行,然後找出對於一行m列所有的放牛情況k個。之後初始化dp數組第一行,將所有的放牛情況與土地情況匹配,如果符合題意那麼dp[1][j]=1。其中j就表示了這行土地中的一種放牛情況。之後的所有行中,我們除了與土地情況匹配,還需要與上一層放牛的情況覈對,看看是否有衝突。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#define INF 0x3f3f3f3f
#define mod 100000000
using namespace std;
int main()
{
int mp[30];
long long dp[20][5000];
int poss[6000];
int n,m,x;
int k=0;
memset(poss,0,sizeof(poss));
memset(mp,0,sizeof(mp));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
if(x==0) //爲了方便土地與放牛的核對,我們將不肥沃的土地標爲1
mp[i] += 1;
if(j!=m) mp[i]<<=1;
}
}
for(int i=0;i<(1<<m);i++) //對於一行m塊地找出所有放牛的情況
{
if(!(i&(i<<1)))
poss[k++]=i;
}
for(int i=0;i<k;i++) //初始化第一行dp數組
{
if(!(poss[i]&mp[1]))
{
dp[1][i]=1;
dp[1][k] ++;
}
}
int sum;
for(int i=2;i<=n;i++)
{
for(int j=0;j<k;j++) //判斷j放牛情況是否符合第i行土地
{
if(!(poss[j]&mp[i]))
{
sum=0;
for(int l=0;l<k;l++) //統計與上一行衝突的數量
{
if(dp[i-1][l]!=0&&(poss[l]&poss[j]))
{
sum+=dp[i-1][l];
}
}
dp[i][j] = dp[i-1][k]-sum;
dp[i][k] = (dp[i][k]+dp[i][j])%mod;
}
}
}
printf("%lld\n",dp[n][k]);
return 0;
}