POJ3254或洛谷1879 Corn Fields

一道状压\(DP\)

POJ原题链接

洛谷原题链接

很显然的状压,\(1\)表示种植,\(0\)表示荒废。
将输入直接进行状压,而要满足分配的草场是适合种草的土地,即是分配时的状态中的\(1\),在输入对应的状态中也是\(1\),而\(0\)对应\(0,1\)都可以。
设输入的这行状态为\(a[i]\),分配时的这行状态为\(x\),则用位运算来表示上述条件即\((\sim a[i])\&x=0\),设其为函数\(judge(i,x)\)
因为每个草场不能相邻,对于每一行,可以先预处理出在二进制下没有\(1\)是相邻的所以数,记录在集合\(S\)中,集合大小为\(l\);对于列上要求不相邻,即上下两行不能有\(1\)相邻,即\(i\&(i-1)=0\)
定义\(f[i][j]\)表示分配至第\(i\)行,第\(i\)行的状态为\(j\)

\(\qquad\qquad f[i][j]=\sum\limits_{k=0,judge(i-1,S[k])\text{且}i\&(i-1)=0}^{l-1}f[i-1][k],\text{其中}i,j\text{满足}judge(i,S[j])\)

最终结果即是\(\sum\limits_{i=0}^{l-1}f[n][i]\)
另外,在\(DP\)时记得对\(10^9\)进行取模。

#include<cstdio>
using namespace std;
const int N = 13;
const int M = 400;
const int mod = 1e9;
int f[N][M], a[N], S[M];
int re()
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c<'0' || c>'9'; c = getchar())
        p = (c == '-' || p) ? 1 : 0;
    for (; c >= '0'&&c <= '9'; c = getchar())
        x = x * 10 + (c - '0');
    return p ? -x : x;
}
bool judge(int x, int y)
{
    if ((~a[x]) & y)
        return false;
    return true;
}
int main()
{
    int i, j, n, m, l = 0, k, o;
    n = re();
    m = re();
    o = 1 << m;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= m; j++)
            a[i] |= (re() << (m - j));
    for (i = 0; i < o; i++)
        if (!(i&(i << 1)))
            k = S[l++] = i;
    f[0][0] = 1;
    for (i = 1; i <= n; i++)
        for (j = 0; j < l; j++)
            if (judge(i, S[j]))
                for (k = 0; k < l; k++)
                    if (judge(i - 1, S[k]) && !(S[j] & S[k]))
                        (f[i][j] += f[i - 1][k]) %= mod;
    for (k = i = 0; i < l; i++)
        (k += f[n][i]) %= mod;
    printf("%d", k);
    return 0;
}

ps:因为我用的是\(VS\),所以代码会自动补空格,而我本来的风格是没有空格的。

猜你喜欢

转载自www.cnblogs.com/Iowa-Battleship/p/9504654.html
今日推荐