#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int M=65;
int n,m,vnum;
int dp[110][M][M]; // dp[i][j][k] 第i行排法为J i-1行排法为k时 前i行最多能排的步兵
int map[110];
int state[M];//原本一行有1024个状态 打表排除掉同行矛盾的状态如:10100后得到 60个状态 节省空间
int num[M];//状态i的放置人数
int getnum(int k) //求二进制中1的个数
{
int res=0;
while(k)
{
k&=k-1;//每次相当于消除最右边的1
res++;
}
return res;
}
void Init()
{
vnum=0;
for(int i=0;i<1024;i++)
{
if(!(i&i<<2||i&i<<1))
{
state[vnum]=i; // 10010代表 位置1和4放置步兵
num[vnum++]=getnum(i);
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
map[i]=0;
for(int j=0;j<m;j++)
{
char c;
cin>>c;
if(c=='P')
map[i]+=(1<<(m-j-1));//第i行的最大状态
}
}
for(int i=0;i<n;i++) //第一行
{
for(int j=0;j<M;j++)
{
for(int k=0;k<M;k++)
{
dp[i][j][k]=-1;
}
}
}
Init();
for(int i=0;i<vnum;i++)
{
if(!(state[i]&(~map[0]))) // 不是平原的不能放
{
dp[0][i][0]=num[i];
}
}
for(int i=1;i<n;i++)
{
for(int j=0;j<vnum;j++)// the state of row i
{
if((state[j]&(~map[i]))) // 不是平原的不能放
continue;
for(int k=0;k<vnum;k++) // the state of row i-1
{
if((state[k]&(~map[i-1])))
continue;
if(state[k]&state[j]) // row i和i-1不能有矛盾
continue;
for(int t=0;t<vnum;t++)
{
if(state[j]&state[t]) //row i和i-2不能矛盾
continue;
if(dp[i-1][k][t]==-1)
continue;
if(state[t]&state[k])
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+num[j]);
}
}
}
}
int ans=0;
for(int j=0;j<vnum;j++)
{
for(int k=0;k<vnum;k++)
{
ans=max(ans,dp[n-1][j][k]);
}
}
cout<<ans<<endl;
return 0;
}
poj 1185状压DP入门
最新推荐文章于 2023-08-08 14:59:34 发布