[洛谷 1879] 玉米田

蒟蒻初学状压DP,做题入门中。。。

题目传送门

概念:

状压DP,就是用进制的方法把多个位置的选取状态压缩成一个变量的动态规划

分析:

在这题中,根据数据范围,我们显然不可能开出 2 ^ 144的数组存储每一个状态,如果用二进制记录状态,所有位置的值无法被表示出来,但是一行12个值是可以被记录,可以被枚举完的

若我们从上往下确定情况的话,第i行的情况只会受到第i-1行的影响,第1~i-2行不会影响第i行,也就是无后效性,故我们可以按行枚举

设f[i][state]表示当前计算到第i行,且枚举第i行的种植情况为state的方案数

则 f[ i ] [ state ] = sigma f( i - 1 , state' ),也就是枚举i - 1行的子集就可以了

当然,根据题意,还存在很多的限制条件:

  1. 第i行的种植情况不能和原有的土地情况冲突
    • state & g [ i ] == g [ i ]
  2. 第i行的state内部不能冲突,不能有左右相邻的1
    • state & (state << 1) == 0 或 state & (state >> 1) == 0
  3. 第i行的state不能和第i-1行的state‘冲突,不能存在相邻两行有上下相邻的1
    • state & state' == 0

那么最后的答案就是f [ m ] [ 0 ] + ... + f [ m ] [ 1 << n - 1 ]

#include <bits/stdc++.h>
const int mod = 1e8;

int n, m, x;
int f[15][1 << 12], g[15];
bool state[1 << 12];

int main()
{
    scanf("%d%d", &m, &n);
    int MaxState = 1 << n;
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d", &x), g[i] = (g[i] << 1) + x;
    for (int i = 0; i < MaxState; i++)
        state[i] = ((i & (i << 1)) == 0) && ((i & (i >> 1)) == 0);

    /* g[i]: state on line i */
    f[0][0] = 1;
    for (int i = 1; i <= m; i++)
        for (int j = 0; j < MaxState; j++)
            if (state[j] && ((j & g[i]) == j))
                for (int k = 0; k < MaxState; k++)
                    if ((k & j) == 0)
                        f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
    int ans = 0;
    for (int i = 0; i < MaxState; i++)
        ans += f[m][i], ans %= mod;
    std::cout << ans << '\n';
    return 0;
}

转载于:https://www.cnblogs.com/wyctstf/p/11335004.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值