POJ3254 Corn Fields(状态压缩DP)

题目链接

分析:

作为状态压缩DP入门题,很好。

由题意可知:

1.任意两牛(包括行和列)不能临近

2.牛只能在有草的即值为1的地方

3.不放牛也为一种方案

定义dp[i][s]为第i行状态s下的方案数。

dp[i][s] = ∑(dp[i-1][s']),其中s'为不与s冲突的状态

注意:

因为位运算优先级很低,所以要多加括号。因此

if((cow & (cow<<1)) != 0) return 0;
和
if(cow & (cow<<1) != 0) return 0;
是不一样的
#include <cstdio>
#include <cstring>

#define MAXN 13
#define MODNUM 100000000

int n, m;
int filter[MAXN];
int dp[MAXN][1<<MAXN];

int check(int cow, int grass){
    if((cow & grass) != cow) return 0;  //检测牛是否都在有草的地方,如果否返回0
    if((cow & (cow<<1))) return 0;  //该行是否有两牛相邻,有就返回0
    return 1;
}

void solve(){
    int i, j, itype, k, ans;
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 1;
    itype = (1<<m);
    for(i=1; i<=n; i++){
        for(j=0; j<itype; j++){
            if(check(j, filter[i])){
                for(k=0; k<itype; k++){
                    if((j&k) == 0){ //保证对于该行j状态与上一行k状态,两行间没有临近的牛
                        dp[i][j] = (dp[i][j] + dp[i-1][k]) % MODNUM;
                    }
                }
            }
        }
    }
    ans = 0;
    for(i=0; i<itype; i++){
        ans = (ans+dp[n][i]) % MODNUM;
    }
    printf("%d\n", ans);
}

int main(){
    int i, j, t;

    scanf("%d %d", &n, &m);

    for(i=1; i<=n; i++){
        filter[i] = 0;
        for(j=0; j<m; j++){
            scanf("%d", &t);
            filter[i] = (filter[i]<<1)+t;   //将每行草地用二进制表示
        }
    }

    solve();

    return 0;
}
原文地址:https://www.cnblogs.com/tanhehe/p/3014334.html