题意: 这题就是传说中的炮兵阵地 洛谷P2704, 题意很简单, 在一个 m × n ( 1 ≤ m ≤ 100 , 1 ≤ n ≤ 10 ) m\times n( 1\leq m \leq100, 1\leq n\leq10) m×n(1≤m≤100,1≤n≤10)的矩阵里面放十字架, 要求十字架的中心不被覆盖, 矩阵为’P’的地方才可以放十字中心, 问最多能放多少个十字架
>> face <<
Strategy:状压DP, i是一个表示二进制的十进制数,'1’该位置已经放置了一个十字中心,代表当前行的状态
状态: 看到题后会比较自然的想出dp[i][j][k]代表目前第i行状态为j,上一行状态为k所能放置的最大十字架数量, 但是很容易会发现dp[101][1<<10][1<<10]会很大, (101 * 1024 *1024 *4 / 1024 /1024 = 404mb, 题目只给了128mb). 一番思索就会发现,对当前行有用的数据只有上一行和上上一行, 于是就可以设计成dp[3][1 << 10][1 << 10]的滚动数组
目标: d p [ m % 3 ] [ i ] [ j ] ∣ m a x dp[m\%3][i][j]\mid_{max} dp[m%3][i][j]∣max最后一行的任意状态和上一行的任意状态的最大值
边界: 如果从第三行推至少需要前两行的信息, 所以边界就是初始化第一行和第二行, 显然,初始化第一行就用用任意合法状态填充, 初始化第二行就可以枚举任意与第一行合法的状态填充就可以了
合法判断: 这里合法判断比较复杂, 推荐把所有的合法状态存下来再做转移,不过我并没有这么做, 日后回顾的时候会注意的
转移方程:
d p [ r % 3 ] [ c u r ] [ l a s t ] = m a x ( d p [ r % 3 ] [ c u r ] [ l a s t ] , d p [ r − 1 % 3 ] [ l a s t ] [ l a s t ] + n u m [ c u r ] ) dp[r\%3][cur][last] = max(dp[r\%3][cur][last], dp[r-1\%3][last][last]+num[cur]) dp[r%3][cur][last]=max(dp[r%3][cur][last],dp[r−1%3][last][last]+num[cur])
attention: 矩阵的 行和列
双倍经验: 两层状压 + 滚动数组优化, 很有价值的一题, 日后定要回顾一下
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define all(a) a.begin(), a.end()
#define met(a, b) memset(a, b, sizeof(a))
#define what_is(x) cout << #x << " is " << x << endl
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define lowbit(x) x &(-x)
#define bin(x) cout << #x << " is " << bitset<10>(x) << endl
#define pi acos(-1.0)
using namespace std;
const int maxn = 1 << 10;
const int mod = 1e8;
int dp[3]<