先看同一行哪一些方案可以放置,以减小时间复杂度(老套路)
查看的方法是看左边第一、二,右边第一、二 不能跟自己这个位置同时有1
然后统计这个方法包含的炮兵数,统计方法是线性dp,通过lowbit(树状数组的东西),转移计数。(每个方案的炮兵数量是这个方案的二进制串去除最低位的1的炮兵数量+1)
最后一行一行向前dp,记住原则,一直统计新的一行的平原,并用二进制串表示,再相邻行不断的判断筛选掉不可行的方案,用dp数组向前推进可行方案,每推进一次更新一次ans的最大值,最终输出ans的最大值即可。。
#include <iostream>
using namespace std;
char map[105][12];
int method[2020],num[2020]; int op[105];
int cnt=0;
int dp[105][500][500];
int lowbit(int x)
{
return x&(-x);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf(" %c",&map[i][j]);
for(int i=0;i<(1<<m);i++)//枚举各个方案,选择能够放置的
{
if(i&(i>>1)) continue;
if(i&(i>>2)) continue;
if(i&(i<<1)) continue;
if(i&(i<<2)) continue;
method[++cnt]=i;
}
for(int i=1;i<(1<<m);i++)
{
num[i]=num[i-lowbit(i)]+1;
}
int ans=0;
for(int i=1;i<=n;i++)//一行一行往前dp
{
for(int j=1;j<=m;j++)
{
op[i]|=((map[i][j]=='H')<<(j-1));
}
for(int j=1;j<=cnt;j++)
{
if(method[j]&op[i]) continue;//存在放置到山地的方案
for(int k=1;k<=cnt;k++)
{
if(method[k]&method[j]) continue;//i-1行与i行冲突
int v=num[method[j]];//存放i行新增的方案数
if(i>=2&&(method[k]&op[i-1])) continue;//i-1行放到了山地上
for(int p=1;p<=cnt;p++)
{
if(method[p] & op[i - 2]) continue;
if((method[p] & method[k]) == 0 && (method[j] & method[p]) == 0)
{
dp[i][j][k] = max(dp[i][j][k],dp[i - 1][k][p] + v);
ans=max(ans,dp[i][j][k]);
}
}
}
}
}
printf("%d\n",ans);
}


京公网安备 11010502036488号