AcWing 292. 炮兵阵地 状态压缩DP,维护最后两行的状态
原题链接
中等
作者:
皓首不倦
,
2020-07-25 16:50:51
,
所有人可见
,
阅读 655
M, N = map(int, input().split())
grid = [0] * M
for i in range(M):
arr = input()
for j in range(N):
if arr[j] == 'P':
grid[i] |= (1 << j)
# 一行状态是否合法
def is_valid(val):
cur_pos = -2
for i in range(10):
if (val & (1 << i)) != 0:
if cur_pos >= 0 and i - cur_pos <= 2:
return False
else:
cur_pos = i
return True
# 先提前计算一行的状态能转换到的另外的一行状态
m = {val:[] for val in range(1<<N) }
for val in range(1 << N):
for new_val in range(1 << N):
if new_val & val == 0 and is_valid(new_val):
m[val].append(new_val)
# 一行状态和山地是否吻合
def is_match(val, mask):
return val & (~mask) == 0
# 1的数量
def one_cnt(val):
ans = 0
while val:
ans += 1
val = val & (val - 1)
return ans
# dp(i, j, k) 表示前i行进行摆放,最后一行二进制状态为j, 倒数第二行二进制状态为k的约束下,所有合法状态中炮的最多数量
dp1 = [[0] * 1100 for _ in range(1100)]
dp2 = [[0] * 1100 for _ in range(1100)]
ans = 0
for i in range(M):
if i == 0:
for j in range(1 << N):
for k in m[j]:
if is_valid(j) and is_match(k, grid[i]):
dp2[j][k] = 1
ans = max(ans, dp2[j][k])
elif i == 1:
for j in range(1 << N):
if not is_match(j, grid[i-1]):
continue
if not is_valid(j):
continue
for k in m[j]:
if is_match(k, grid[i]):
dp2[j][k] = one_cnt(j) + one_cnt(k)
ans = max(ans, dp2[j][k])
else:
for j in range(1 << N):
if not is_match(j, grid[i-1]):
continue
if not is_valid(j):
continue
for k in m[j]:
if is_match(k, grid[i]):
dp2[j][k] = one_cnt(j) + one_cnt(k)
max_val = 0
for next_stat in m[j | k]:
if not is_valid(next_stat):
continue
if not is_match(next_stat, grid[i-2]):
continue
max_val = max(max_val, dp1[next_stat][j])
dp2[j][k] = max(dp2[j][k], max_val + one_cnt(k))
ans = max(ans, dp2[j][k])
# 滚动数组
dp1, dp2 = dp2, dp1
print(ans)