目录:
题目:
分析:
先用二进制表示每一行的是否可以放置的状态。
然后用
state[i]
s
t
a
t
e
[
i
]
来表示只计算单行第
i
i
种状态是否合法。
然后每次将状态左移和右移一位然后用&运算判断是否合法就行了。
之后我们开始dp
用表示第i行第j种状态的方案数。然后我们枚举上一行的状态
k
k
,然后判断两个状态是否合法。
对于的初始化,则是
f[0][0]
f
[
0
]
[
0
]
等于1
代码:
#pragma GCC optimize("Os")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int state[4096],t[13][13],e[13],f[13][4096];
int main()
{
/* freopen("cowfood.in","r",stdin);
freopen("cowfood.out","w",stdout);*/
int n=read(),m=read(),ms;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
t[i][j]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
e[i]=(e[i]<<1)+t[i][j];
ms=1<<m;
for(int i=0;i<ms;i++)
state[i]=((i&(i<<1))==0)&&((i&(i>>1))==0);
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<ms;j++)
if(state[j]&&((j&e[i])==j))
for(int k=0;k<ms;k++)
if((k&j)==0)
f[i][j]=(f[i][j]+f[i-1][k])%1000000000;
int ans=0;
for(int i=0;i<ms;i++)
ans=(ans+f[n][i])%1000000000;
printf("%d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}