题目链接:点击打开链接
题意 :中文。。就不啰嗦了 大致就是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; }
原文:http://blog.csdn.net/qq_16255321/article/details/41701857