标签:dp
题目链接:点击打开链接
题意 :中文。。就不啰嗦了 大致就是n*m的格子上放置炮兵,相邻两格不能放,求最大放置个数。
思路:就是典型的状压啦,dp[i][j][k] 代表当前行状态为s[j],前一行状态状态为 s[k] 时的最大放置个数。状态转移方程可为
dp[i][j][k] =max(dp[i][j][k],dp[i-1][k][p]+sum[j]) (枚举上上行的状态p sum[j] 为状态s[j] 可以放置的炮兵的个数,可以预处理得到)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cctype>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define maxn 1<<12
#define _ll __int64
#define ll long long
#define INF 0x3f3f3f3f
#define Mod 1000000007
#define pp pair<int,int>
#define ull unsigned long long
using namespace std;
char ma[105][15];
int n,m,s[66],sum[66],dp[110][66][66],cur[110],tot;
int get_sum(int x)
{
int ans=0;
while(x)
{
if(x&1)ans++;
x>>=1;
}
return ans;
}
void init()
{
int num=1<<m;tot=0;
for(int i=0;i<num;i++)
{
if((i&(i<<1))||(i&(i<<2)))continue;
s[tot]=i;sum[tot++]=get_sum(i);
}
}
bool check(int x,int y)
{
if(x&y)return 0;
return 1;
}
void solve()
{
memset(dp,0,sizeof(dp));
for(int i=0;i<tot;i++)
if(check(s[i],cur[1]))
dp[1][i][0]=sum[i];
for(int i=2;i<=n;i++)
{
for(int j=0;j<tot;j++)
{
if(!check(s[j],cur[i]))continue;
for(int k=0;k<tot;k++)
{
if(!check(cur[i-1],s[k]))continue;
if(!check(s[j],s[k]))continue;
if(i==2)
{
dp[i][j][k]=sum[j]+dp[i-1][k][0];
}
else
{
for(int sb=0;sb<tot;sb++)
{
if(!check(cur[i-2],s[sb]))continue;
if(!check(s[sb],s[j]))continue;
if(!check(s[sb],s[k]))continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][sb]+sum[j]);
}
}
}
}
}
int ans=-1;
for(int i=0;i<tot;i++)
for(int j=0;j<tot;j++)
ans=max(ans,dp[n][i][j]);
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(cur,0,sizeof(cur));
for(int i=1;i<=n;i++)
{
scanf("%s",ma[i]+1);
for(int j=1;j<=m;j++)
if(ma[i][j]=='H')
cur[i]+=1<<(m-j);
}
init();
solve();
}
return 0;
}
标签:dp
原文地址:http://blog.csdn.net/qq_16255321/article/details/41701857