【洛谷 P1902 】刺杀大使|二分答案 + DFS
一、题目分析
题意简述
迷宫是 n×m 的网格:
- 第 1 行所有格子是入口,伤害值全为 0
- 第 n 行每一格都有机关,必须全部走到
- 除首尾两行外,房间有激光伤害 p[i][j]
- 士兵路径上所有格子的伤害最大值为该士兵代价
- 可以派出多名士兵,全队代价 = 所有士兵代价里的最大值
- 求全队最小的最大伤害代价
核心考点拆解
-
最小值最大化模型:典型二分答案场景 —— 我们二分一个伤害上限 mid,验证是否存在方案:所有第 n 行机关都能通过伤害≤mid的路径从第 1 行入口抵达。
-
连通性校验:二分的判定函数用 DFS/BFS,只走伤害≤当前二分值的格子,看能否覆盖全部终点(第 n 行)。
-
网格搜索:四向移动,边界判断、访问标记防回头重复搜索。
解题思路总览(二分答案模板逻辑)
- 二分区间:伤害值域 [0, 1000],左边界 l=-1,右边界 r=1001
- 二分判定:给定限制值 mid,只允许走 p[i][j] ≤ mid 的格子,从第 1 行全部起点出发,看第 n 行所有单元格是否连通
- 二分收缩:
- 若能连通全部终点:说明 mid 可行,尝试更小值,r=mid
- 若不能连通:限制太小,需要放大伤害,l=mid
- 最终结果:r 就是满足条件的最小最大伤害
二、算法原理详解
1. 二分答案为什么适用?
题目求「所有士兵路径伤害最大值的最小取值」,满足二分单调性:
- 如果伤害上限 X 可行(能走完所有机关),那么所有大于 X 的数值一定可行
- 如果 X 不可行,所有小于 X 的数值一定不可行
单调区间可以通过二分快速逼近最优解,把 "求最优值" 转化为 "给定值做连通性判断",时间复杂度大幅优化。
2. DFS 判定函数作用
给定伤害阈值 z,仅遍历网格中 p[x][y] ≤ z 的格子,标记可达区域。
判定逻辑:第 n 行所有单元格都被标记可达 → 阈值 z 合法。
3. 时间复杂度估算
- 二分次数:值域 0~1000,最多二分 10 次
- 单次 DFS:网格最多 1005×1005,单次遍历 O(nm)
- 总复杂度:O(10 × n × m),对于 n,m≤1000 完全通过,不会超时
三、完整可 AC 修正代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
int n,m,p[N][N];
bool vis[N][N];
bool dfs(int x,int y, int z){
if(x==n) return true;
vis[x][y] = true;
for(int i=0; i<4; i++){
int newx = x+dx[i];
int newy = y+dy[i];
if(newx>=1 && newx<=n&&newy>=1&&newy<=m&&!vis[newx][newy]&&p[newx][newy]<=z)
if(dfs(newx,newy,z)) return true;
}
return false;
}
int find(){
int l = -1, r = 1001;
while(l+1<r){
int mid = l+r>>1;
memset(vis,0,sizeof vis);
if(dfs(1,1,mid)) r = mid;
else l = mid;
}
return r;
}
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1; j<=m;j++){
cin>>p[i][j];
}
}
cout<<find();
return 0;
}
四、样例推演(输入 #1)
输入样例:
4 2
0 0
3 5
2 4
0 0
网格伤害矩阵:
行1:0 0
行2:3 5
行3:2 4
行4:0 0
二分过程:
- mid=5:所有格子都能走,第 4 行全部连通,可行,记录 ans=5,缩小右边界
- mid=2:只能走伤害≤2 的格子,第二行 5、第三行 4 无法通行,第四行右列不可达,不可行
- mid=3:伤害上限 3,路径:
- (1,1)→(2,1)(伤害 3)→(3,1)(伤害 2)→(4,1)
- (1,2) 向下无法走 5,横向连通 (1,1) 绕左路到达第四行两格,全部机关覆盖
最终最小合法值为 3,和样例输出匹配。
五、总结
洛谷 P1902 "刺杀大使" 是一道经典的二分答案 + 连通性检验题目,主要考察:
- 二分答案思想:将最优化问题转化为判定问题
- 网格连通性:DFS/BFS 遍历可达区域
- 边界条件处理:注意起点是整行,终点也是整行
- 时间复杂度控制:二分 + 搜索的组合在合理范围内
掌握这道题后,可以举一反三解决类似的 "最小值最大化" 或 "最大值最小化" 问题,这类问题在算法竞赛中非常常见。
关键点:一定要从第 1 行的所有入口开始搜索,不能只从 (1,1) 开始,这是本题最容易出错的地方。
浙公网安备 33010602011771号