POJ 3254 Corn Fields

题目大意:农夫约翰有一个M*N的矩形牧场,想在牧场里面种植一些植物,但是这些植物不能够相邻,而且有些地是不能种植的,求共有多少种种植方式。


解题思路:把每一行的状态用二进制的数表示,1表示在该处种植植物,反之,用0表示。根据题意可知:两个相邻的行或者列不能同时为1,且不能种植植物的地方用0表示。用dp[state][i]表示状态为state时,到第i行符合条件的方案数

则状态转移方程为:dp[state][i] =Sigma dp[state'][i-1] (state'为符合条件的所有状态) dp[state][1] =1(state符合条件) OR 0 (state不符合条件)


代码实现如下:


#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#define mod 100000000
int M, N, top = 0;
int state[600], num[110];
int dp[20][600];
int cur[20];

bool ok(int x)
{
    if(x & x << 1) return 0;
    return 1;
}

void init()
{
    top = 0;
    int total = 1 << N;
    for(int i = 0; i < total; i ++)
    {
        if(ok(i)) state[++top] = i;
    }
}

bool fit(int x, int k)
{
    if(x & cur[k]) return 0;
    return 1;
}

int jcount(int x)
{
    int cnt = 0;
    while(x)
    {
        cnt ++;
        x = x & (x-1);
    }
    return cnt;
}
int main()
{
    while(~scanf("%d %d", &M, &N))
    {
        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;
                for(int j = 1; j <= top; j ++)
                {
                    if(!fit(state[j], i-1)) continue;
                    if(state[k] & state[j]) continue;
                    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\n", ans);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值