玉米田 (cowfood) hgoi0422 题解
题目描述
- FJ 购买了一处肥沃的矩形牧场,分成 M N(1 M 12; 1 N 12) 个格子。他想
在那里的一些格子中种植美味的玉米。遗憾的是,有些格子区域的土地是贫瘠的,不能耕
种。
精明的 FJ 知道奶牛们进食时不喜欢和别的牛相邻,所以一旦在一个格子中种植玉米,
那么他就不会在相邻的格子中种植,即没有两个被选中的格子拥有公共边。他还没有最终
确定哪些格子要选择种植玉米。
作为一个思想开明的人,FJ 希望考虑所有可行的选择格子种植方案。由于太开明,他
还考虑一个格子都不选择的种植方案!请帮助 FJ 确定种植方案总数。
输入
- 第一行包括两个用空格分隔的整数 M 和 N。
接下来的 M 行,每行 N 个数,描述了每行格子是否可以种植的情况(1 表示肥沃的、
适合种植,0 表示贫瘠的、不可种植)。
输出
- 输出一个整数,表示 FJ 可选择的方案总数 mod 10^8 的结果。
样例
- 输入样例
- 2 3
1 1 1
0 1 0 - 输出样例
- 9
- 数据范围
- 对于 60% 的数据,1 M; N 6
对于 100% 的数据,1 M; N 12
题目解析
- 此题主要考察的是状压DP。
- 简单读题,不难发现此题对于某个坐标只有其上下左右会影响。
- 思考后可以将每一行作为dp的一个阶段,只有其上一行对自己会产生影响。
而可将每一行的状态进行压缩,使用二进制0表示种,1表示不种,将一整行化为一个int。 - 于是使用 f [ i ][ j ] 代表前i行状态为j的总方案数
- 那么 f [ i ][ j ]=∑f [ i -1 ][ k ] (此处的k代表所有可行的状态)
- 需要注意的是再枚举状态时需要先判断自己是否可行,再判断与上一行是否冲突。
附上AC程序
时间复杂度 O (m*n^2)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
int able[13];
int m,n,f[13][1<<12];
void finit(){
freopen("cowfood.in","r",stdin);
freopen("cowfood.out","w",stdout);
}
bool check(int tar,int row){
if (tar&(~able[row])) return false;
for (int i=0;i<n-1;i++)
if (((3<<i)&tar)==(3<<i))
return false;
return true;
}//判断目标状态是否可行
int main(){
finit();
cin>>m>>n;
int t;
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++){
cin>>t;
able[i]<<=1;
able[i]+=t;
}//读入农田,将每一行化为二进制数列方便判断
for (int i=0;i<(1<<n);i++)
if (check(i,1))
f[1][i]=1;
for (int i=2;i<=m;i++)
for (int j=0;j<(1<<n);j++)
if (check(j,i))
for (int k=0;k<(1<<n);k++)
if (!(k&j)){
f[i][j]+=f[i-1][k];
f[i][j]%=100000000;
}//dp,对所有可行状态方案数进行累加
int res=0;
for (int i=0;i<1<<n;i++){
res+=f[m][i];//统计最终解
res%=100000000;
}
cout<<res;//输出答案
return 0;
}