【题意】中文题目,题意很简单!

【解题方法】

首先我们求的是最多能放多少个炮兵,那么假如我把所有的情况都枚举了,然后在得到的结果里面找一个最大值,那么是不是就可以了。其实这个题目的思想就是这么简单。

但是我们如果用一般的枚举的方法肯定会超时,那么就用到了状态压缩。因为这个题目中一个炮影响的是两行,所以我们要多定义一维的状态来表示当前行的上上一行的状态。 状态:dp【i】【j】【k】 第 i 行,状态为 k ,第 i-1 行状态为 j 的最大放的炮兵数目

转移方程 dp [ i ] [ j ] [ k ]  = max ( dp [ i ] [ j ] [ k ] , dp [ i - 1 ] [k ] [ l ] + num [ j ] )

【AC代码和详细解释】

// //Created by just_sort 2016/12/21 //Copyright (c) 2016 just_sort.All Rights Reserved // //#include <ext/pb_ds/assoc_container.hpp> //#include <ext/pb_ds/tree_policy.hpp> //#include <ext/pb_ds/hash_policy.hpp> #include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> //isstringstream #include <iostream> #include <algorithm> using namespace std; //using namespace __gnu_pbds; typedef long long LL; //typedef pair<int, LL> pp; #define REP(i, n) for(int i = 0; i < n; i++) #define REPZ(i, n) for(int i = 1; i <= n; i++) #define MP(x,y) make_pair(x,y) const int maxn = 1100; const int maxm = 1<<12; const int inf = 0x3f3f3f3f; //typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set; //head int n, m, num[110], top; //记录每一行拥有的炮兵的个数 int st[70], cur[110];//每一行的转态和输入的地的状态 int dp[110][70][70]; //dp[i][j][k]在第i行状态为j,在第i-1行状态为k的最大方案数 bool judge1(int x)//判断二进制相邻的1或者间隔2个位置,即是炮兵横着不能攻击到 { if(x&(x<<1) || x&(x<<2)) return false; else return true; } bool judge2(int i, int k)//判断当前行和上一行的状态是否出现冲突 { return cur[i] & st[k]; } void init1() //关键数组初始化 { memset(num, 0, sizeof(num)); memset(st, 0, sizeof(st)); memset(cur, 0, sizeof(cur)); memset(dp, 0, sizeof(dp)); top = 0; } void init2() //对不必要的状态进行剔除 { int total = 1 << m; for(int i = 0; i < total; i++) { if(judge1(i)) st[++top] = i; } } //int cal(int x) //计算状态x里面1的个数 //{ // int cnt = 0; // while(x) // { // if(x&1) cnt++; // x >>= 1; // } // return cnt; //} int main() { while(scanf("%d%d", &n, &m)!=EOF) { init1(); init2(); char x; int ans = 0; for(int i = 1; i <= n; i++) //输入的地的状态 { getchar(); for(int j = 1; j <= m; j++) { scanf("%c", &x); if(x =='H') cur[i] += (1 << (j-1)); } } //初始化DP装态 for(int i=1; i<=top; i++) { num[i] = __builtin_popcount(st[i]); if(!judge2(1, i)) { dp[1][i][1] = num[i]; //第1行状态为i,第0行状态为 ans = max(ans, num[i]); //更新一下当前最大值 } } //状态转移 for(int i = 2; i <= n; i++) //枚举行 { for(int j = 1; j <= top; j++)//当前行状态 { if(judge2(i, j)) continue; for(int l = 1; l <= top; l++) //上上行状态 { if(st[j] & st[l]) continue; for(int k = 1; k <= top; k++){ //上一行状态 if(st[j] & st[k]) continue; dp[i][j][k] = max(dp[i][j][k], dp[i-1][k][l] + num[j]); //状态转移 ans = max(ans, dp[i][j][k]); //更新答案 } } } } //输出答案 printf("%d\n", ans); } return 0; }