poj3254(状态压缩dp)

//状态转移方程: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;
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值