/*
真值表:a为状态(放牛为1,不放牛为0);b为场地状态(1为可以放,0为不能放)
a b F
0 0 1 //不放牛 场地也不允许放 没问题真值为1
0 1 1 //不放牛 场地可以放 没问题
1 0 0 //放牛 但场地不能放 错误 真值为0
1 1 1 //放牛 场地可以放 没问题
由真值表 得F=(~a)|b=!(a&(~b)); 可以看到b是要取反的 所以在读入的时候要对场地取反
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
#define maxn 1<<12
#define MOD 100000000
using namespace std;
int state[maxn];//填充一行 ,所有可行状态
int current_state[13];//i行的场地状况
int num_state;//state的大小
int dp[13][maxn];//dp[i][j] i为行数 j为第j个状态
bool state_ok(int x,int y)//检验状态x和状态y能否相邻 不能 return 0 否则return 1;
{
return !(x&y); //相邻状态不能同时为1
}
void find_state_of_one_row(int m)//寻找填充一行(该行所有的格子都是1,都是fertile)的所有可行状态
{
int i;
num_state=0;
m=1<<m;
for(i=0;i<m;++i)
{
if(state_ok(i,i<<1))//将状态i平移一位,检验是否有两只羊相邻的情况
{
state[num_state++]=i;
}
}
return ;
}
int main()
{
memset(dp,0,sizeof(dp));
memset(current_state,0,sizeof(current_state));
int n,m;
scanf("%d%d",&n,&m);
int i,j;
for(i=0;i<n;++i)
{
for(j=0;j<m;++j)
{
int temp;
scanf("%d",&temp);
if(!temp)
{
current_state[i]+=(1<<j);
//F=(~a)|b=!(a&(~b)); a为填充一行的可行状态,b为当前场地的状态(能不能放牛);此处为对b取反 即(~b)
}
}
}
find_state_of_one_row(m);
for(i=0;i<num_state;++i)//初始化第一行的可行状态数
{
if(state_ok(state[i],current_state[0]))//判断该状态能否放在该行 F=(~a)|b=!(a&(~b)); state为a , current_state为(~b)
{
dp[0][i]=1;
}
}
int k;
for(i=1;i<n;++i)
{
for(j=0;j<num_state;++j)//选取上一行的可用状态
{
if(dp[i-1][j]==0) continue;
for(k=0;k<num_state;++k)//选取本行的状态
{
if(state_ok(state[k],current_state[i]) && state_ok(state[j],state[k]))//该状态可以放到i行并且可以和上一行的j状态相邻
{
dp[i][k]=(dp[i][k]+dp[i-1][j])%MOD;//第k个状态可行 并且可能有多个j状态可以与k状态相邻 所以是+=;
}
}
}
}
int ans=0;
for(i=0;i<num_state;++i)
{
ans=(ans+dp[n-1][i])%MOD;
}
printf("%d\n",ans);
}
poj3254 状压DP
最新推荐文章于 2022-07-11 12:07:29 发布