1. 程式人生 > >【狀壓DP】poj3254 Corn Fields

【狀壓DP】poj3254 Corn Fields

一行 cstring fields while state 條件 style 狀壓 ()

題意:
一塊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\n",ans); } return 0; }

【狀壓DP】poj3254 Corn Fields