/**
解题思路:首先将原图每一行当做一个二进制数,按位取反得到另一个十进制数。然后求出在所给的列的范围内的合法状态,即没有任意两个1相邻,放入数组legal中,每种合法状态对应数组的一个下标。再单独求出第一行的所有可行状态,将dp[0][i]初始化。最后求出下面的每一行的可行状态,即跟本行的上一行不冲突且在本行可行。累加结果即可求出答案。
*/
/**
题目大意:给出M,N,M行N列的一块儿田地,矩阵用0、1填充。1代表该土地肥沃,可以种庄稼,0代表贫瘠,不可种。但是要求不能有相邻的种法,因为庄稼可能互相影响。问一共有多少种方式去种庄稼,所有都不种也算是一种方式。
/**
状态压缩:用二进制或三进制等进制的各位数字来代表一种
状态,用以解决问题的方法。
*/
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MOD 100000000
int n,m,all;
const int MAXN=1<<15;
int dp[15][MAXN];
int Map[15],legal[MAXN];
bool jud_legal(int x){ //二级制表示时没有相邻的1
if(x&(x<<1))
return false;
return true;
}
void solve_legal(){
all=0; //记录共有多少个合法状态
for(int i=0;i<(1<<m);i++){
if(jud_legal(i)){
legal[all++]=i; //每个合法状态都和一个数组下标对应
}
}
}
int main(){
while(cin>>n>>m){
memset(Map,0,sizeof(Map));
memset(dp,0,sizeof(dp));
memset(legal,0,sizeof(legal));
solve_legal(); //解出合法状态,即二进制没有相邻的两个1的数
for(int i=0;i<n;i++){
for(int j=1;j<=m;j++){
int tmp;
cin>>tmp;
if(!tmp){
//把每行都当做一个二进制数,求该行的反
Map[i]+=(1<<(m-j));
}
}
}
for(int i=0;i<all;i++){
//初始化dp的第一行
if(!(legal[i]&Map[0])){
//如果按位与后为假,说明该合法状态可行
dp[0][i]=1;
}
}
for(int i=1;i<n;i++){
for(int j=0;j<all;j++){
if(!(legal[j]&Map[i])){
//如果找到当前行的合法可行状态,则遍历加上与上一行不冲突的可行状态数
for(int k=0;k<all;k++){
if(dp[i-1][k]!=0){
if(!(legal[k]&legal[j])){
//如果上一行的可行状态跟当前行可行状态不冲突
dp[i][j]=(dp[i][j]+dp[i-1][k])%MOD;
}
}
}
}
}
}
int ans=0;
for(int i=0;i<all;i++){
//所有可行结果都在最后一行
ans=(ans+dp[n-1][i])%MOD;
}
cout<<ans<<endl;
}
return 0;
}
*/