刚开始的思路是 把0-2^x的 所有状态枚举, 然后找符合条件的, 但是 发现 当12*12 时 1的数量x 超过64 这是个庞大的数字, 跟本就没法枚举;
想到用状态压缩, 但是 怎么压缩才行 ?
作为这是状态压缩入门题, 感觉 废了好大力气;
【思路】
把每一行 0/1状态 转换成 十进制的数, 每一行看成一个整体, 进行压缩,
【第一步】
先提前处理 相邻两项不符合条件的 例如 001 和 011 这样的就不符合 (违背相邻两项不种植条件)
【第二步】
为了可以找到符合条件的, 在进行输入时 处理, 把 输入的 010 进行 取反 得到的是 101 目的是 & =0; 找到当前行 满足条件的
例如 示例 第二行 010, 那么只有 010 和 000 才能放在这 010 取反为 101 , 101 & 010 =0 101 & 000 =0 这是符合条件的
【第三步】
找到当前行符合条件的, 那么进行筛选, 筛选出 既不能与前一行 相邻, 又不能与 之前到找的 重复 ;
找到后 累加到当前行中, 用dp【】【】 存储
dp【i】【j】 代表 第 i 行 状态 j 时 符合条件数目;
方程 dp【i】【j】 = Sigma dp 【i-1】【k】 k代表所有符合的 项
【代码】
//#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
#define S1(n) scanf("%d",&n)
#define SL1(n) scanf("%I64d",&n)
#define S2(n,m) scanf("%d%d",&n,&m)
#define SL2(n,m) scanf("%I64d%I64d",&n,&m)
#define Pr(n) printf("%d\n",n)
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int INF=0x3f3f3f3f;
const ll MOD=1e8;
const int MAXN=1e5+5;
const int N=1000;
ll qpow(ll x,ll n){ll res=1;for(;n;n>>=1){if(n&1)res=(res*x);x=(x*x);}return res;}
using namespace std;
int dp[N][N];
int cur[MAXN];
int state[MAXN];
int cot;
int n,m;
void init()
{
int bits= 1<<m;
cot=0;
for(int i=0;i<bits;i++)
{
if( (i&(i<<1))==0 )// 去除相邻的两项
state[++cot]=i;
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();//提前处理所以不相邻的数据
for(int i=1;i<=n;i++)
{
int x;
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
if(x==0)
{
cur[i]+= (1<< (m-j)); // 取反 目的是 将 后面的重复项去掉, 例如 010 取反为 101 & 010 =0
}
}
}
mem(dp,0);
for(int i=1;i<=cot;i++)
{
if( (state[i]&cur[1]) ==0)// 边界状态
dp[1][i]=1;
}
/* for(int i=1;i<=cot;i++)
{
printf("%d | %d\n",state[i],cur[i]);
}*/
for(int i=2;i<=n;i++)// 从第二行开始
{
for(int j=1;j<=cot;j++)
{
if( (state[j]&cur[i])==0 ) //符合条件 当前行
{
for(int k=1;k<=cot;k++)
{
if( ((state[k]&cur[i-1])==0) && ((state[k]&state[j])==0 ) )// 并且不与前一行重复,找到的两个值一样
{
//printf("%d***\n",state[k]);
dp[i][j]= (dp[i][j]+ dp[i-1][k]) %MOD;
}
}
}
}
}
int ans=0;
for(int i=1;i<=cot;i++)
ans = (ans+dp[n][i])% MOD;
printf("%d\n",ans);
}
}
/*
12 12
1 0 1 0 1 0 1 0 1 1 1 1
0 0 1 0 0 1 0 0 0 1 1 1
1 0 0 0 1 1 0 1 0 0 0 1
1 0 1 1 1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 0 0 1 0 1 0 1 0 1
1 1 0 1 0 1 1 0 1 0 1 0
0 0 0 1 0 1 0 1 0 1 0 0
1 0 0 0 1 0 1 0 1 0 0 0
1 0 1 0 1 0 1 1 0 1 0 1
*/