动态规划晋级——POJ 3254 Corn Fields【状压DP】

转载请注明出处:http://blog.csdn.net/a1dark

分析:刚开始学状压DP比较困难、多看看就发现其实也没有想象中那么难、这道题由于列数较小、所以将行压缩成二进制来看、首先处理第一行、先判断同一行中不能有相邻的1出现、然后判断1出现的位置要与题目中的不冲突、接下来就是转移了、从上一行转移到这一行、首先判断上下不能有1相邻、然后就是将上一行的状态转移到当前行、上一行的所有符合条件的状态的总的方案数就是当前行该状态的方案数、

#include <cstdio>
#include <cstring>
using namespace std;
#define mod 100000000
int M,N,top = 0;
int state[600],num[110];
int dp[20][600];
int cur[20];
bool ok(int x){//判断有没有连续的1
   if(x&x<<1)return 0;
   return 1;
}
void init(){
   top = 0;
   int total = 1 << N;//total种状态数
   for(int i = 0; i < total; ++i){
       if(ok(i))state[++top] = i;//如果满足状态就加入到state中
   }
}
bool fit(int x,int k){//判断状态X是否与第K行状态冲突
   if(x&cur[k])return 0;
   return 1;
}
int main(){
    while(scanf("%d%d",&M,&N)!= EOF){
       init();//初始化
       memset(dp,0,sizeof(dp));//初始化
       for(int i = 1; i <= M; ++i){
           cur[i] = 0;
           int num;
           for(int j = 1; j <= N; ++j){
                scanf("%d",&num);
               if(num == 0)cur[i] +=(1<<(N-j));
           }
       }
       for(int i = 1;i <= top;i++){
           if(fit(state[i],1)){//判断是否符合题目给定状态、
                dp[1][i] = 1;
           }
       }
       for(int i = 2; i <= M; ++i){
           for(int k = 1; k <= top; ++k){
                if(!fit(state[k],i))continue;//满足第I行和当前行的状态不冲突
                for(int j = 1; j <= top ;++j){
                    if(!fit(state[j],i-1))continue;//满足第I-1行和上一行的状态不冲突、貌似可以不用
                    if(state[k]&state[j])continue;//相邻两行的对应位置的点的0,1状态不能相同
                    dp[i][k] = (dp[i][k] +dp[i-1][j])%mod;//从上一行转移到当前行
                }
           }
       }
       int ans = 0;
       for(int i = 1; i <= top; ++i){
           ans = (ans + dp[M][i])%mod;
       }
       printf("%d
",ans);
   }
}


原文地址:https://www.cnblogs.com/suncoolcat/p/3357866.html