描述
Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can’t be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.
Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.
输入
Line 1: Two space-separated integers: M and N
Lines 2…M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)
输出
Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.
样例输入
2 3
1 1 1
0 1 0
样例输出
9
题意:
给定M*N的矩阵,每一个单元是一块田,有肥沃和贫瘠之分,只有肥沃的可以种玉米并把牛养在这里,且每头牛都有点小脾气,不想相邻地有其他的牛,问有几种种玉米的方法并对结果对1e9取模(全不种也算一种)。
思路:
首先暴力搜索不可行复杂度为O(2^(all)),all为肥沃田的个数,时间复杂度爆炸。分析过后,可以知道,暴力搜索的过程中,重复构造了许多子状态,浪费了许多时间,那么我们为什么不牺牲一点空间去储存这些子状态呢?要存一个矩阵的状态也有点麻烦,那么我们干脆再次分解子过程,按行递推。
那么怎么记录一行的各个子状态呢?由题可知列数N<=12,那么可以把每一格看成二进制的一位,比如(101)就表示在该行地1,3块地种了玉米。
于是我们可以根据所给条件求出每一行的所有可行状态,并把他们存起来,这样就解决了行内的冲突,对于某一行某一状态的方案数,只要枚举上一行所有状态,并将不冲突的状态方案数累加即可。
由于每次递推的过程中只涉及处理行与它的上一行,所以可以只开 [2][Ms]的状态记录数组即可。
代码:
#include<stdio.h>
const int mod=1e9,Ms=1<<12;
int dp[2][Ms],scheme[2][Ms],cnt[2];
bool check(int x)//判断该状态是否存在相邻情况
{
return !(x&(x<<1));
}
void cake(int no,int n)
{
cnt[no]=0;
for(int i=0;i<=n;i++)
{
if((i|n)!=n)continue;//该状态是否满足题目所给只能种在肥沃田的条件
if(check(i))scheme[no][cnt[no]++]=i;
}
}
int main()
{
int n,m,a[12]={},x;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&x);
a[i]=a[i]*2+x;//肥沃田全种的状态
}
}
int pre=1,now=0;
cake(now,a[0]);
for(int i=0;i<cnt[now];i++)dp[now][scheme[now][i]]++;
for(int u=1;u<n;u++)
{
pre^=1;now^=1;
cake(now,a[u]);//求出当前行所有可行状态
for(int i=0;i<cnt[now];i++)
{
int k1=scheme[now][i],k2;
dp[now][k1]=0;
for(int j=0;j<cnt[pre];j++)
{
k2=scheme[pre][j];
if((k1&k2)==0)//上一行状态与此行状态不冲突
{
dp[now][k1]=(dp[now][k1]+dp[pre][k2])%mod;//累加方案数
}
}
}
}
int ans=0;
for(int i=0;i<cnt[now];i++)ans=(ans+dp[now][scheme[now][i]])%mod;//统计最后一行所有方案数的个数
printf("%d\n",ans);
return 0;
}
若有什么错误,欢迎指正^ _ ^ 。