題意
給你一個n*m的矩陣(農田),1表示可以種植,0表示不能種植。且上下和左右每個單元不能相鄰。問有多少種種植方法(可以不種植)。
樣例
Sample Input
2 3
1 1 1
0 1 0
Sample Output
9
1 2 3
0 4 0
種植一棵樹(1,2,3,4)4種,兩棵(13,14,34)3種,三棵(134)1種,零棵樹1種,sum = 4+3+1+1 = 9。
題解
第一行可行狀態有
1 0 0,0 1 0,0 0 1,1 0 1,0 0 0 。 5種
第二行可行狀態是
0 0 0(1狀態),0 1 0(2狀態)
1狀態下可行下第一行可行狀態有全5種,2狀態可行下有(1 0 0, 0 0 1,1 0 1,0 0 0)4種。總共9種。
所以dp的轉移方程式
dp[i][state] +=dp[i-1][pre_state] = dp[i-1][pre_state(k1)]+dp[i-1][pre_state(k2)]+......+dp[i-1][pre_state(km)]
即此行狀態可行時,上一行滿足的狀態總和就是此狀態的可行情況。那麼此行的可行狀態就是此行所有可行狀態總和。
所以ans = dp[n][state(j1)]+dp[n][state(j2)]+...+dp[n][state(jm)]。
代碼
#include<cstdio>
#include<algorithm>
#include<string.h>
#include <string.h>
using namespace std;
typedef long long ll;
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;
ll 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("%I64d", ans);
}
return 0;
}