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;
 }

你可能感兴趣的:(poj3254(状态压缩dp))