//状态转移方程:dp[i][k]=求和(dp[i-1][t])(其中k和t是上下没有一个庄稼在同一行,这个状态怎么表示就是用压缩,比如上一行是101,这一行是010就可以)所以dp[i][5]肯定包含dp[i][2]
//&运算,按位与运算
//比如8&10,其中8的二进制是0000 1000,而10的二进制是0000 1010,因此
// 0000 1000(十进制8)
// & 0000 1010(10进制10)
//结果为0000 1000(就是10进制的8)
//因此8&10的结果为8
//与的计算规则是,如果两个数都都为真(或为1),其结果为真,如果两位数中有一位为假(或为0)者结果为假
#include <stdio.h>
#include <string.h>
#include <math.h>
int n,m,a[15];
int dp[13][200005];
int check(int x,int flag)
{
int i,temp=3;
if((a[x]&flag)!=flag)//判断下那一行种是否能够找出flag这个状态
return 0;
if((flag&(flag<<1))!=0||(flag&(flag>>1))!=0)
return 0;
return 1;
}
void solve()
{
int i,j,k,max,sum=0;
memset(dp,0,sizeof(dp));
dp[0][0]=1;
max=(1<<m)-1;//指m位二进制最多能表示的十进制
for (i=1;i<=n;i++)
{
for (j=0;j<=max;j++)
{
if (check(i,j)==0)//如果不符合这一行状态(即根本不可能出现)
continue;
for (k=0;k<max;k++)//如果j是一个可能的状态,则比较j与k(如果j与k没有同一个位置上都种庄稼)
{
if ((j&k)!=0)
continue;
dp[i][j]=dp[i][j]+dp[i-1][k];
dp[i][j]=dp[i][j]%100000000;
}
}
}
for (i=0;i<max;i++)
{
sum=sum+dp[n][i];
sum=sum%100000000;
}
printf("%d\n",sum);
}
int main()
{
int x;
while(scanf("%d%d",&n,&m)==2)
{
int i,j;
for (i=1;i<=n;i++)
{
a[i]=0;//每一行的状态认为是000000000
for (j=1;j<=m;j++)
{
scanf("%d",&x);
a[i]=(a[i]<<1)+x;//相当于a[i]*2+x即把多位2进制压缩成一个十进制数
}
}
solve();
}
return 0;
}
poj3254(状态压缩dp)
最新推荐文章于 2022-07-06 15:20:00 发布