Petya and Spiders【二进制状压】

时间:2023-03-09 16:33:00
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 = << ;//6*7=42;
int dp[][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 << ) | (b >> ) | a | c;
return (t&lim) == lim;
}
int main ()
{
scanf("%d%d", &n, &m);
if(n < m) swap(n, m);
memset(dp, -, sizeof(dp));
lim = ( << m) - ;
for(int i = ; i <= lim; i++)
{
dp[][][i] = ;
int t = i;
while(t)
{
if(t & ) nu[i]++;
t >>= ;
}
nu[i] = m - nu[i];
}
for(int i = ; i < n; i++)
for(int j = ; j <= lim; j++) //i行的状态
for(int k = ; k <= lim; k++) //i+1行的状态
if(dp[i][j][k] != -)
{
for(int l = ; l <= lim; l++) //i+2行的状态
if(OK(j, k, l))
dp[i + ][k][l] = max(dp[i + ][k][l], dp[i][j][k] + nu[k]);
}
int ans = ;
for(int i = ; i <= lim; i++)
ans = max(ans, dp[n][i][]);
printf("%d\n", ans);
return ;
}