炮兵阵地 poj 1185

ac的第一题状态压缩的dp。状态涉及前两行,通过“加一维”的方式能够解决。还要注意由于炮兵的限制,能够符合的所有排列其实非常少(远小于2^10,据说在70个左右)知道这一点,预处理出所有可能的状态,再通过其他限制条件(地形,前两行状态)进行筛选。
F[i,j,k]表示第i行,i-1行的状态为j,i-2行状态为k。不包括第i行最多能布置多少炮兵。F[i+1,v,j] = MAX( F[i+1,v,j],F[i,j,k] + sum[v] )。sum[v]表示v排列(行排列)有多少个炮兵。状态转移的要求是v,j,k兼容,并且v与第i行地形兼容。
所以枚举 i,j,k,v 效率 O( n*PSB^3 ) PSB表示所有可能的行排列

 
  
#include < iostream >
#include
< assert.h >
#include
< stdlib.h >
using namespace std;

#define MAX(a,b) ((a)>(b)?(a):(b))
// 垂直方向上的兼容判断 也可判断状态是否适应地形
#define FIT(a,b) (!((a)&(b)))

const int _D_MAXN = 110 ;
const int _D_MAXM = 11 ;
const int _D_POSSIBLE = 100 ;
const int _D_MINEST = - 1000000 ;

int _gn,_gm,_gpbCnt,_gmap[_D_MAXN];
int _gposb[_D_POSSIBLE],_gsum[_D_POSSIBLE],_gdp[_D_MAXN][_D_POSSIBLE][_D_POSSIBLE];

int _fcnt( int s )
{
int cnt = 0 ;
for ( int i = 0 ;i < _gm; ++ i )
if ( s & ( 1 << i) ) ++ cnt;
return cnt;
}

void _fgetPossible() // init _gposb
{
_gpbCnt
= 0 ;
// 注意_gposb[0] = 0;
for ( int i = 0 ,tot = 1 << _gm;i < tot; ++ i )
{
if ( (i & (i << 1 ) || (i & (i << 2 ))) ) continue ; // 水平 相邻1距离在2以上
if ( (i & (i >> 1 ) || (i & (i >> 2 ))) ) continue ;
_gposb[_gpbCnt]
= i;
_gsum[_gpbCnt
++ ] = _fcnt(i);
}
}

void _finit()
{
cin
>> _gn >> _gm;
_fgetPossible();
char c;
for ( int i = 0 ;i < _gn; ++ i )
{
_gmap[i]
= 0 ;
for ( int j = 0 ;j < _gm; ++ j )
{
cin
>> c;
if ( c == ' H ' ) _gmap[i] |= ( 1 << j); // 山地
}
for ( int p1 = 0 ;p1 < _gpbCnt; ++ p1 )
for ( int p2 = 0 ;p2 < _gpbCnt; ++ p2 )
_gdp[i][p1][p2]
= _D_MINEST;
}
}

int main()
{
// system("pause");
_finit();
// // 第二行 初始化
// for( int sc = 0;sc < _gpbCnt;++sc )
// {
// int ns = _gposb[sc];
// if( FIT(ns,_gmap[0]) ) _gdp[1][sc][0] = MAX(_gdp[1][sc][0],_gsum[sc]);
// }

_gdp[
0 ][ 0 ][ 0 ] = 0 ;
for ( int i = 0 ;i < _gn; ++ i )
{
for ( int j = 0 ;j < _gpbCnt; ++ j )
for ( int k = 0 ;k < _gpbCnt; ++ k )
{
if ( _gdp[i][j][k] == _D_MINEST ) continue ;
for ( int sc = 0 ;sc < _gpbCnt; ++ sc )
{
int ns = _gposb[sc];
if ( FIT(ns,_gposb[j]) && FIT(ns,_gposb[k]) && FIT(ns,_gmap[i]) ) // ok ns符合要求
_gdp[i + 1 ][sc][j] = MAX(_gdp[i + 1 ][sc][j],_gdp[i][j][k] + _gsum[sc] );
}
}
}

int ans = _D_MINEST;
for ( int j = 0 ;j < _gpbCnt; ++ j )
for ( int k = 0 ;k < _gpbCnt; ++ k )
ans
= MAX(ans,_gdp[_gn][j][k]); // _gn行不在地图上 但是答案在上面
cout << ans << endl;

// cout << "----------------------" << endl;
// cout << _gpbCnt << endl;
// cout << _gposb[0] << endl;

return 0 ;
}

转载于:https://www.cnblogs.com/code-/articles/2038323.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值