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 ;
}
#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 ;
}