Petya and Spiders【二进制状压】

题目链接【http://codeforces.com/problemset/problem/111/C】

题意:给出大小为N*M的图(1 ≤ n, m ≤ 40, n·m ≤ 40),每个图中有一个蜘蛛,每个蜘蛛有5种运动状态,不动,向上下左右移动。问蜘蛛如何移动才能使得图中的空地数最大,输出最大空地数。

题解:虽然(1 ≤ n, m ≤ 40, n·m ≤ 40),但是当(n<m)的时候可以swap(n,m),对结果是没有影响的。用一个二进制数表示每一行的每个位置的状态。最多有(1<<6)-1种状态,如果该位置是1 表示该位置可以容纳蜘蛛,反之不能放入蜘蛛。

dp[i][j][k]为第i行的状态为j,i+1行的状态为k的空位数。 dp[i + 1][k][l] = max(dp[i + 1][k][l], dp[i][j][k] + nu[k]);这个第(i+1)行的转移方程是满足在第i、第(i+1)行、第(i+2)行的状态使得(i+1)行的蜘蛛的有去处。最后取DP[n][i][0]的最大值。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1 << 6;//6*7=42;
int dp[45][maxn][maxn];//dp[i][j][k]为第i行的状态为j,i+1行的状态为k的空位数
int nu[maxn];
int n, m, lim;
bool OK (int a, int b, int c)
{
    int t = b | (b << 1) | (b >> 1) | a | c;
    return (t&lim) == lim;
}
int main ()
{
    scanf("%d%d", &n, &m);
    if(n < m) swap(n, m);
    memset(dp, -1, sizeof(dp));
    lim = (1 << m) - 1;
    for(int i = 0; i <= lim; i++)
    {
        dp[0][0][i] = 0;
        int t = i;
        while(t)
        {
            if(t & 1) nu[i]++;
            t >>= 1;
        }
        nu[i] = m - nu[i];
    }
    for(int i = 0; i < n; i++)
        for(int j = 0; j <= lim; j++) //i行的状态
            for(int k = 0; k <= lim; k++) //i+1行的状态
                if(dp[i][j][k] != -1)
                {
                    for(int l = 0; l <= lim; l++) //i+2行的状态
                        if(OK(j, k, l))
                        dp[i + 1][k][l] = max(dp[i + 1][k][l], dp[i][j][k] + nu[k]);
                }
    int ans = 0;
    for(int i = 0; i <= lim; i++)
        ans = max(ans, dp[n][i][0]);
    printf("%d\n", ans);
    return 0;
}

 

posted @ 2016-12-30 10:53  _Mickey  阅读(301)  评论(0编辑  收藏  举报