题目描述
农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
输入格式
第一行:两个整数M和N,用空格隔开。
第2到第M+1行:每行包含N个用空格隔开的整数,描述了每块土地的状态。第i+1行描述了第i行的土地,所有整数均为0或1,是1的话,表示这块土地足够肥沃,0则表示这块土地不适合种草。
输出格式
一个整数,即牧场分配总方案数除以100,000,000的余数。
输入输出样例
输入 #1
2 3
1 1 1
0 1 0
输出 #1
9
分析
它的基本思想就是用二进制来优美地暴力枚举出现的方案,
若二进制下第ii位有赋值1,则一行的第i列有放牛
那么f[i][j]表示在前ii行中(包括 i )在 j 个状态下的最大方案数
易得
f
[
i
]
[
j
]
=
(
f
[
i
]
[
j
]
+
f
[
i
−
1
]
[
k
]
)
m
o
d
p
f[i][j]=(f[i][j]+f[i−1][k]) mod p
f[i][j]=(f[i][j]+f[i−1][k])modp
,j 是第 i 行的状态,k是第 i−1 行的状态)
所以我们还要再预处理一下,v[i]表示第 i 个状态是否存在.
目标状态: f [ n ] [ i ] f[n][i] f[n][i]全部相加
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
const int p=100000000;
ll f[15][1<<12],n,m;
ll a[20][20],h[1<<12],ff[20],v[1<<12];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ff[i]=(ff[i]<<1)+a[i][j];
}
}
for(int i=0;i<=(1<<m)-1;i++)
{
if(!(i&(i>>1))&&!(i&(i<<1)))
{
v[i]=1;
if((i&ff[1])==i) f[1][i]=1;
}
}
for(int i=2;i<=n;i++)
{
for(int j=0;j<=(1<<m)-1;j++)
{
if((j&ff[i-1])==j&&v[j])
{
for(int k=0;k<=(1<<m)-1;k++)
{
if((k&ff[i])==k&&!(j&k)&&v[k])
{
f[i][k]=(f[i][k]+f[i-1][j])%p;
}
}
}
}
}
int ans=0;
for(int i=0;i<=(1<<m)-1;i++)
{
ans=(ans+f[n][i])%p;
}
cout<<ans;
return 0;
}