> 这是一道非常经典的插头DP(luogu)题目。结合数据范围 min(n,m) <= 6 且 K <= 15,我们可以确定这题需要用轮廓线DP来解决。下面是这道题的完整思路拆解和C++代码实现。
核心思路拆解
1. 状态设计
因为伤害是由周围8个方向的炮塔决定的,所以我们不仅要记录轮廓线上的插头连通性,还要记录轮廓线上每个格子的具体类型。我们定义轮廓线上的状态:
* 0:障碍(#)
* 1:路径(.)
* 3:炮塔(X)
对于插头连通性,使用标准的括号表示法:1 为左括号,2 为右括号。但由于本题可能产生不闭合的连通块(例如起点和终点),我们需要引入 3 表示独立插头。
综合起来,状态可以设计为 f[阶段][炮塔数量][轮廓线状态],其中轮廓线状态包含了每个格子的类型和插头信息。
2. 转移与分类讨论
在逐格转移时,我们需要根据当前格子的左插头 pl1 和上插头 pl2 进行分类讨论:
* 遇到原有障碍:只能填障碍,且 pl1 和 pl2 必须为 0。
* 遇到空地/起点/终点:
* 如果 pl1 == 0 && pl2 == 0:可以放炮塔、放障碍,或者新建一个独立连通块(填路径并产生独立插头)。
* 如果只有一个插头为 0:直接延伸另一个插头。
* 如果 pl1 == 1 && pl2 == 2 或 pl1 == 2 && pl2 == 1:合并连通块或删除插头。
* 如果 pl1 == 1 && pl2 == 1 或 pl1 == 2 && pl2 == 2:需要在轮廓线上寻找匹配的括号进行替换。
* 涉及独立插头 3 的情况:需要向左或向右寻找匹配的括号进行替换。
* 注意:pl1 == 1 && pl2 == 2 会形成非法的闭合回路,直接跳过。
3. 伤害计算
由于伤害是累加的,我们可以在转移时计算当前格子放置炮塔或路径时对周围已经确定的格子造成的伤害。为了简化,可以在整个DP结束后,遍历最终合法状态(S和T连通且炮塔数<=K),统计所有路径格子受到的总伤害。
C++ 代码实现