題目鏈接:
http://poj.org/problem?id=1185
題目大意:
中文題。
範圍:
N <= 100;M <= 10。
思路:
狀壓dp。
還是將炮兵擺放的地方設1,不放的地方設0。
因爲他對炮兵的攻擊範圍做了要求,也就是相鄰的炮兵位置不能小於2。那麼我們就要先篩選出滿足這個硬性條件的狀態。
然後我們可以發現,對於第i行的狀態,與上一行以及上上一行有關。
所以考慮設一個三維dp[i][j][k],代表到第i行時,第i行的狀態爲j,第i-1行的狀態爲k時候的最大的可以擺放的數量。
這樣我們就可以得到轉移方程:dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]),這裏num[j]表示在第i行的狀態j裏面放了多少個炮兵,也就有多少個1。
代碼:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,kk;
int dp[105][110][110],cur[105],state[110],num[110];
bool ok(int x)
{
if(x&(x<<1))return 0;
if(x&(x<<2))return 0;
return 1;
}
void init()
{
for(int i=0;i<(1<<m);i++)
{
if(ok(i)){state[kk++]=i;
}
}
}
int cal(int x) //計算x的狀態下有多少個1;
{
int ans=0;
while(x)
{
ans++;
x&=(x-1);
}
return ans;
}
bool judge(int x,int y)
{
return x&y;
}
int main()
{
char c;
int i,j,k,l;
while(~scanf("%d%d",&n,&m))
{
kk=0;
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
memset(cur,0,sizeof(cur));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>c;
if(c=='H')cur[i]+=(1<<(m-j));
}
init();
for(i=0;i<kk;i++)
{
num[i]=cal(state[i]);
if(!judge(cur[1],state[i]))
{dp[1][i][0]=num[i]; //邊界處理
}
}
for(i=2;i<=n;i++)
{
for(j=0;j<kk;j++)
{
if(judge(cur[i],state[j]))continue;
for(k=0;k<kk;k++)
{
if(judge(state[j],state[k]))continue;
for(l=0;l<kk;l++)
{
if(judge(state[k],state[l]))continue;
if(judge(state[j],state[l]))continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]);
}
}
}
}
int ans=0;
for(j=0;j<kk;j++)
for(k=0;k<kk;k++)
ans=max(ans,dp[n][j][k]);
printf("%d\n",ans);
}
}