3254: 玉米田(POJ)
题目描述
约翰购买了由m ×n (1≤m ,n ≤12) 的方格组成的矩形牧场,想在一些方格上种玉米。遗憾的是,有些方 格土壤贫瘠,无法种植。约翰在选择种植哪些方格时,会避免选择相 邻的方格,没有两个选定的方格共享一条边。约翰考虑了所有可能的 选择,他认为没有选择方格也是一种有效的选择!帮助他选择种植方 格的方案数。
输入
第1行包含以两个空格分隔的整数m 和n。后面有m 行, 每行都包含n 个整数,表示一个方格是否肥沃(1表示肥沃,0表示贫瘠)。
输出
单行输出选择种植方格的方案数模100000000。
样例输入
2 3
1 1 1
0 1 0
样例输出
9
提示信息
按如下方式对肥沃的方格进行编号,仅在一个方格上种植 有4种方案(1、2、3或4),在两个方格上种植有3种方案(13、14或 34),在三个正方形上种植有1种方案(134),还有1种方案是所有方 格都不种植。所以一共有9种方案。
题解1(C++版本)
#include<cstdio>
using namespace std;
const int MOD = 100000000;
int m, n; //玉米田行数、列数
int g[14]; //用十进制数保存每行的状态值,用二进制表示状态
int dp[14][1<<14]; //dp[i][a]表示已经种植前i行,第i行第a个状态时的方案数
int cnt; //一行的合法状态个数
int s[1<<14]; //一行的合法状态集,每行的初始合法状态集是相同的
int main(){
scanf("%d%d", &m, &n);
for(int i = 1; i <= m; i++){
for(int j = 1,x; j <= n; j++){
scanf("%d", &x);
g[i] = (g[i]<<1) + x; // 输入三个数(1 1 1),则g[i]=111
}
}
// 预处理
for(int i = 0; i < (1<<n); i++){ //枚举一行所有的状态
if(!(i&(i>>1))) s[cnt++] = i; //保存一行的初始合法状态
}
dp[0][0] = 1; //什么都不种植,也是一种方案
for(int i = 1; i <= m + 1; i++){ //枚举行
for(int a = 0; a < cnt; a++){ //枚举第i行的初始合法状态
for(int b = 0; b < cnt; b++){ //枚举第i - 1行的初始合法状态
if((s[a]&g[i]) == s[a] && !(s[a]&s[b])){ //题目中的约束条件
dp[i][a] = (dp[i][a] + dp[i - 1][b]) % MOD;
} //'&'运算符的优先级低于'=='运算符的优先级
}
}
}
printf("%d\n", dp[m + 1][0]); //相当于只在1~n行种植
return 0;
}