poj 1185 炮兵阵地(三维状态压缩dP)

时间:2022-06-18 00:08:49

题目:http://poj.org/problem?id=1185

思路:

d[i][j][k]表示第i行的状态为第k个状态,第i-1行的状态为第j个状态的时候 的炮的数量。

1表示放大炮, 地形状态中1表示山地。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define max(a, b) (a) > (b)?(a):(b) int cnt, c[], m, n;
char map[][], num[];
int d[][][], cur[];
bool ok(int x) //判断一行中,是否合法
{
if(x&(x<<)) return false;
if(x&(x<<)) return false;
return true;
}
void init() //初始计算这n个 有多少种合法的状态
{
int i;
cnt = ;
for(i = ; i < (<<n); i++)
if(ok(i))
c[++cnt] = i;
}
bool fit(int x, int k) //判断当前行的状态是否与 地形合法
{
if(cur[k]&x) return false;
return true;
}
int cal(int x)
{
int sum = ;
while(x)
{
sum++;
x = (x&(x-)); //计算一行中1的个数,相当于每次都减去1个1
}
return sum;
}
int main()
{
int i, j, k, t, ans;
while(~scanf("%d%d", &m, &n))
{
if(n== && m==)
break;
init();
for(i = ; i <= m; i++)
scanf("%s", map[i]);
for(i = ; i <= m; i++)
{
cur[i] = ;
for(j = ; j < n; j++)
{
if(map[i][j]=='H')
cur[i] += ;
if(j != n-)
cur[i] = (cur[i]<<);
}
}
memset(d, -, sizeof(d)); for(i = ; i <= cnt; i++) //初始第1行
{
num[i] = cal(c[i]);
if(fit(c[i], ))
d[][][i] = num[i];
}
for(i = ; i <= m; i++)
for(t = ; t <= cnt; t++)
{
if(!fit(c[t], i))
continue;
for(j = ; j <= cnt; j++)
{
if(c[t]&c[j]) continue; //判断与上上行合法
for(k = ; k <= cnt; k++)
{
if(c[t]&c[k]) continue; //判断与上行合法
if(d[i-][j][k]==-) continue;
d[i][k][t] = max(d[i][k][t], d[i-][j][k]+num[t]);
}
}
} ans = ;
for(i = ; i <= m; i++)
for(j = ; j <= cnt; j++)
for(k = ; k <= cnt; k++)
ans = max(ans, d[i][j][k]);
printf("%d\n", ans);
}
return ;
}