炮兵阵地 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;
}