题目链接
题意:P处放大炮H不可放,黑色区域为攻击范围,求大炮不能相互攻击的情况下,安装最多的大炮数.
分析:三维状压DP
一开始乱写了一通,真不知道写的是什么,竟然过了样例,欺骗了自己???
看了题解要提前把状态预处理一下,其实也就60个状态满足,然后三维状压,突然灵感来了。
仔细一想,二维就够了呀,上去就是写一个二维状压???不过样例???
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
u
]
+
n
u
m
[
v
i
s
[
j
]
]
)
;
dp[i][j]= max(dp[i][j], dp[i - 1][u] + num[vis[j]]);
dp[i][j]=max(dp[i][j],dp[i−1][u]+num[vis[j]]); 仔细再一想,不对。第i行的所有状态不能转移到第i + 1行状态,按照二维的写法,第i + 1行的所有状态会推到第i + 2行的所有状态,但是有可能第i行的所有状态不满足第i + 2行的所有状态,所以这个方程不对。。。
应该开三维,
d
p
[
i
]
[
j
]
[
u
]
=
m
a
x
(
d
p
[
i
]
[
j
]
[
u
]
,
d
p
[
i
−
1
]
[
u
]
[
v
]
+
n
u
m
[
v
i
s
[
j
]
]
)
dp[i][j][u] = max(dp[i][j][u], dp[i - 1][u][v] + num[vis[j]])
dp[i][j][u]=max(dp[i][j][u],dp[i−1][u][v]+num[vis[j]]),把上一状态也记录一下,这样就不会出现上面二维出现的问题。
PS:状态的预处理值得mark.
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e8;
const int MAXN = 110;
int dp[110][65][65], num[1 << 11];
int a[MAXN], vis[65];
int p = 0, n, m; char ch;
bool judge(int x) {
if(x & (x << 1)) return false;
if(x & (x << 2)) return false;
return true;
}
inline void init() {
for(int i = 0; i < (1 << m); ++i) {
if(!judge(i)) continue;
vis[p++] = i;
int x = i;
while(x) {
if(x & 1) num[i]++;
x >>= 1;
}
// printf("%d %d\n",i, num[i]);
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%d %d", &n, &m); init();
for(int i = 1; i <= n; ++i) {
getchar(); int ans = 0;
for(int j = 1; j <= m; ++j) {
scanf("%c", &ch);
if(ch == 'P') ans = (ans << 1) + 1;
else ans = (ans << 1);
}
a[i] = ans;
}
for(int i = 0; i < p; ++i) {
if((a[1] & vis[i]) != vis[i]) continue;
dp[1][i][i] = num[vis[i]];
}
for(int i = 0; i < p; ++i) {
if((a[2] & vis[i]) != vis[i]) continue;
for(int j = 0; j < p; ++j) {
if(((a[1] & vis[j]) != vis[j]) || (vis[i] & vis[j])) continue;
dp[2][i][j] = max(dp[2][i][j], dp[1][j][j] + num[vis[i]]);
}
}
for(int i = 3; i <= n; ++i) {
for(int j = 0; j < p; ++j) {
if((a[i] & vis[j]) != vis[j]) continue;
for(int u = 0; u < p; ++u) {
if((vis[j] & vis[u]) || ((a[i - 1] & vis[u]) != vis[u])) continue;
for(int v = 0; v < p; ++v) {
if((vis[v] & vis[u]) || (vis[v] & vis[j]) || ((a[i - 2] & vis[v]) != vis[v])) continue;
dp[i][j][u] = max(dp[i][j][u], dp[i - 1][u][v] + num[vis[j]]);
}
}
}
}
int sum = 0;
for(int i = 0; i < p; ++i) {
for(int j = 0; j < p; ++j) {
sum = max(sum, dp[n][i][j]);
}
}
printf("%d\n", sum);
return 0;
}