状态压缩。
感想:我也才学状态dp,确实逻辑思想得很强,看了半天大神的代码才把思想搞清楚,不说了,我这么搓的智商都A出来了,骚年还等什么啦。
思路:应该学过dp的都知道这题得用状态压缩来解决。状态压缩DP。很经典的状态压缩DP。用int型来表示每行的状态(如果int型的二进制的第i位为1,则表示这一行的第i列有安装大炮)。
这样的话由于最多有10列,故由计算可得最多有60种状态。(代码中的ok()函数就可以用来算这个值,不会位运算的可以baidu下)。DP部分:dp[r][i][k]表示第r行的状态为k,第r-1行的状态为i时候,
前r行最多能够安装的大炮数量。
#include<iostream>
#include<cstring>
#define N 65
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
int sum[N],sta[N];
int map[101];
int dp[2][N][N];//滚动数组
int cnt = 0,row,col;
bool ok(int x)//判断这种情况是否合理
{
if(x&(x<<1)) return false;
if(x&(x<<2)) return false;
return true;
}
int getsum(int x)//x的2进制表示一共有多少个1,也就是这行共有多少个炮
{
int num = 0;
while(x>0)
{
if(x&1) ++num;
x >>= 1;
}
return num;
}
void fint(int x)//预处理求出多有可能的状态。
{
int g = 1<<x;//x此处表示列数就ok
for(int i=0;i<g;++i)
if(ok(i))
{
sta[cnt] = i;
sum[cnt] = getsum(i);
++cnt;
}
}
int main(void)
{
cin>>row>>col;
memset(dp,-1,sizeof(dp));
for(int i=0;i<row;++i)
for(int j=0;j<col;++j)
{
char tmp;
cin>>tmp;
if(tmp=='H')
{
map[i] |= (1<<j);
}
}
fint(col);
//第一行进行特殊处理
for(int i=0;i<cnt;++i)
if(!(sta[i]&map[0]))
dp[0][0][i] = sum[i];
for(int r=1;r<row;++r)
for(int j=0;j<cnt;++j)//这个是状态
{
if(map[r]&sta[j]) continue;
for(int k=0;k<cnt;++k)
{
if(sta[j]&sta[k]) continue;
{
for(int e=0;e<cnt;++e)
{
if(sta[j]&sta[e]) continue;
if(dp[(r-1)%2][e][k]==-1) continue;
dp[r%2][k][j] = max(dp[r%2][k][j],dp[(r-1)%2][e][k]+sum[j]);
}
}
}
}
int ans = 0,hh = (row-1)%2;
for(int i=0;i<cnt;++i)
for(int j=0;j<cnt;++j)
if(dp[hh][i][j]>ans)
ans = dp[hh][i][j];
cout<<ans<<endl;
return 0;
}