P2704 [NOI2001]炮兵阵地

只能说还是不会状压dp。。

这道题看上去很熟悉,就是n国王问题,只不过多了一些限制。

题目还会给你一个地图,告诉你那些地方不能放国王,那么用二进制存下来这个状态,判断的时候&一下即可。

这道题的国王的手变长了,是上下左右各两格,所以我们在定义状态的时候应该注意,在判断不可能的解的时候要左移和右移两位&一&。

定义状态我本来想定义四维的,但是发现你会爆空间。但是放国王要考虑到当前行和上面两行的啊!

其实最上面一行是可以被滚掉的,你不定义也可以,不信的话看代码。

其他的就没有什么大问题了。

代码:

#include<cstdio>
#include<algorithm>
const int maxn = 102, maxm = 12, maxM = 1048;
int stdd[maxn];
int status[maxM], tot;
long long dp[maxn][maxM][maxM];
int n, m;
int all;
#define lowbit(x) (x & -x)
int getsum(int x)
{
    int ans = 0;
    while(x)
    {
        x -= lowbit(x); ans++;
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
    {
        char ch[maxm]; scanf("%s", ch);
        for(int j = 0; j < m; j++)
        {
            stdd[i] <<= 1;
            if(ch[j] == 'H') stdd[i] |= 1;
        }
    }
    all = (1 << m) - 1;
    for(int i = 0; i <= all; i++)
    {
        if(i & (i << 1)) continue;
        if(i & (i << 2)) continue;
        if(i & (i >> 1)) continue;
        if(i & (i >> 2)) continue;
        status[++tot] = i;
        if(!(i & stdd[1])) dp[1][i][0] = getsum(i);
    }
    for(int i = 1; i <= tot; i++)// 2nd row
    {
        if(stdd[2] & status[i]) continue;
        for(int j = 1; j <= tot; j++)// 1st row
        {
            if(stdd[1] & status[j]) continue;
            
            if(status[i] & status[j]) continue;
            dp[2][status[i]][status[j]] = std::max(dp[2][status[i]][status[j]], dp[1][status[j]][0] + getsum(status[i]));
        }
    }
    for(int i = 3; i <= n; i++)
    {
        for(int j = 1; j <= tot; j++)// ith row
        {
            if(stdd[i] & status[j]) continue;
            for(int k = 1; k <= tot; k++)// i-1th row
            {
                if(stdd[i - 1] & status[k]) continue;

                if(status[j] & status[k]) continue;
                for(int l = 1; l <= tot; l++)// i-2th row
                {
                    if(stdd[i - 2] & status[l]) continue;

                    if(status[l] & status[j]) continue;
                    if(status[l] & status[k]) continue;
                    dp[i][status[j]][status[k]] = std::max(dp[i][status[j]][status[k]], dp[i - 1][status[k]][status[l]] + getsum(status[j]));
                }
            }
        }
    }
    long long ans = 0;
    for(int i = 1; i <= tot; i++)
        for(int j = 1; j <= tot; j++)
            ans = std::max(ans, dp[n][status[i]][status[j]]);
    printf("%lld\n", ans);
}
posted @ 2018-08-30 15:14  Garen-Wang  阅读(182)  评论(0编辑  收藏  举报