POJ3254 Corn Fields

【题目大意】一个矩阵里有很多格子,每个格子有两种状态,
可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,
在这块牧场放牛,要求两个相邻的方格不能同时放牛,
即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)

有个技巧就是把可放牧的与不可放牧的地方都取反 方便后面的状态比较
我看的这个博客的题解
http://blog.csdn.net/y990041769/article/details/24658419

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
#include <stack>
#include <string>
#include <map>
#include <set>
#define pi acos(-1)
#define LL long long
#define ULL unsigned long long
#define inf 0x3f3f3f3f
#define INF 1e18
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef pair<int, int> P;
const int maxn = 1e5 + 5;
const int mod = 1e8;

LL dp[13][1<<12];
int mp[13], sta[1<<12]; // 存状态的数组 satae 
int n, m;
int judge(int s) // 判断二进制是否有相邻 1 
{
    return s & (s << 1);
}
int main(void)
{
//  freopen("C:\\Users\\wave\\Desktop\\NULL.exe\\NULL\\in.txt","r", stdin);
    int i, j, k, S, t, cnt;
    LL ans;
    while (cin >> n >> m)
    {
        memset(sta, 0, sizeof(sta));
        memset(mp, 0, sizeof(mp));
        memset(dp, 0, sizeof(dp));
        for (i = 1; i <= n; i++){
            for (j = 1; j <= m; j++){
                scanf("%d", &t);
                if (t == 0)
                    mp[i] += 1<<(j-1);
            }
        }
        cnt = 0;
        for (S = 0; S < (1<<m); S++)
            if (!judge(S))
                sta[++cnt] = S;
        for (i = 1; i <= cnt; i++)
            if (!(mp[1] & sta[i]))
                dp[1][i] = 1;
        for (i = 2; i <= n; i++){
            for (j = 1; j <= cnt; j++){
                if (mp[i] & sta[j]) continue; //  判断当前行 能否按 当前状态放 
                for (k = 1; k <= cnt; k++){
                    if (mp[i-1] & sta[k])   // 判断当前这个状态是否可以放在 前一行 
                        continue;       // 不符合就pass  相当于一个剪枝            
                    if (sta[j] & sta[k]) //这个判断的是 当前状态 是否与上一行 相邻 
                        continue; 
                    dp[i][j] = (dp[i][j] + dp[i-1][k]) % mod;// 若符合  则当前行可按 当前状态放 
                }
            }
        }
        ans = 0;
        for (i = 1; i <= cnt; i++)
            ans = (ans + dp[n][i]) % mod;
        printf("%lld\n", ans);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值