原题链接 poj 1185 炮兵阵地
由于每行只有十个可以考虑用状态压缩,又由于每行两炮之间不能小于2,故可以先计算出,最多不会超过60种
状态,可以先存下这些状态(f[]),然后存下每种状态的炮阵地数量(num[]),用dp[][][];
状态转移公式 dp[i][j][k]=num[j]+max(dp[i-1][k][t])(其中j与k相符,j与t也要相符) (ps:相符是指,同一列 两者的阵地不能相冲)
我是新手 代码有危险:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1<<10
using namespace std;
char map[105][12];
int dp[105][66][66];//dp[i][j][k]第i行,取第j种状态且上一行取第k种状态
int f[62];//存的是所有可能的状态值
int num[62];//每种状态对应的摆放数。
int n,m;
bool check(int p1,int u)//初始化中保证每行不能有两个相差小于2
{
int tt=2;
int nu=0;
for(int i=0; i<m; i++)
{
if((u>>i)&1)
{
nu++;
if(tt<2)return false;
tt=0;
continue;
}
tt++;
}
num[p1]=nu;
return true;
}
void init()//初始化出所有可能的状态,不考虑地形的。。。
{
int p1=0;
for(int i=0; i<(1<<m); i++)
if(check(p1,i))
f[p1++]=i;
f[p1]=(1<<m);
}
bool ck(int s,int u)
{
for(int i=0; i<m; i++)
if(((u>>i)&1)&&map[s][i]=='H')
return false;
return true;
}
int pk(int i,int j,int k)
{
int ans=0;
for(int t=0;f[t]<(1<<m);t++)
{
if(f[j]&f[t])continue;
ans=max(ans,dp[i-1][k][t]);
}
return ans;
}
int solve()
{
memset(dp[1],0,sizeof(dp[1]));
for(int i=0;f[i]<(1<<m); i++)//对dp初始化
if(ck(1,f[i]))
dp[1][i][0]=num[i];
else
dp[1][i][0]=0;
for(int i=2;i<=n;i++) //当前是第几行
{
for(int j=0;f[j]<(1<<m);j++)//当前选哪个状态
{
for(int k=0;f[k]<(1<<m);k++) //上一行选哪个状态
{
dp[i][j][k]=0;
if(!ck(i,f[j])||(f[j]&f[k]))continue;//根据当前地形判断此状态是否合理 以及 j和上一行的k是否相容。
dp[i][j][k]=num[j]+pk(i,j,k);
}
}
}
int ans=0;
for(int i=0;f[i]<(1<<m);i++)
for(int j=0;j<(1<<m);j++)
ans=max(ans,dp[n][i][j]);
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{ getchar();
for(int i=1; i<=n; i++)
scanf("%s",map[i]);
init();
printf("%d\n",solve());
}
return 0;
}