poj 3254 状态压缩dp

/*
限制条件
 1.同行不能相邻
 2.上下不能相邻
 3.不能在零的地方放东西
解:
  求出各行合法的状态,为第一行的和法状态赋值为1
  从上到下合并状态dp[i][j]=(dp[i][j]+dp[i-1][k])%mod(其中j。k 为i和i-1行合法的状态)
  也就是说把上一行的状态数目存储到dp[i][0]中了。
*/
#include<stdio.h>
#include<string.h>
#define mod 100000000
#define N  15
int lower[N];
int ss[1<<13];
int n,m,ma[N][N],total,dp[N][700],sum[N][700];//因为len最大不超过700
int judge(int i,int j) {
int k;
for(k=0;k<m;k++)
   if((lower[k]&j)&&ma[i][k+1]==0)
   return 0;
return 1;
}
void slove() {
  int i,j,k,len=0;
  memset(dp,0,sizeof(dp));
  for(i=0;i<(1<<m);i++) {
    if(i&(i<<1))continue;
    ss[len++]=i;
  }
       for(i=1;i<=n;i++)
        for(j=0;j<len;j++)
        if(judge(i,ss[j]))//判断在本行合法的状态
         sum[i][j]=1;
       for(i=0;i<len;i++)
    if(sum[1][i])
        dp[1][i]=1;
    for(i=2;i<=n;i++)
    for(j=0;j<len;j++) {
            if(sum[i][j]==0)continue;
        for(k=0;k<len;k++){
            if(sum[i-1][k]==0)continue;
          if(ss[j]&ss[k])continue;
           dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
       //    printf("%d %d %d
",ss[j],ss[k],dp[i][j]);
        }
    }
    total=0;
    for(i=0;i<len;i++)
        if(sum[n][i])
            total=(total+dp[n][i])%mod;//所有的状态值和
        return ;
}
int main() {
    int i,j;
    lower[0]=1;
    for(i=1;i<=13;i++)
        lower[i]=lower[i-1]*2;
    while(scanf("%d%d",&n,&m)!=EOF) {
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
            scanf("%d",&ma[i][j]);
            slove();
        printf("%d
",total);
    }
return 0;
}

原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410609.html