1 条题解
-
0
题目理解
这是一个玩家与海盗的博弈问题:
- 地图是
N x M
网格,包含海洋(.
)、陆地(I
)、玩家(Y
)、海盗(V
)、宝藏(T
) - 玩家先移动,然后海盗移动,这算一回合
- 失败条件:玩家与海盗在同一行或同一列,且中间没有陆地阻挡
- 胜利条件:玩家到达宝藏点且没有失败
关键点是:玩家必须选择一条固定路线,无论海盗如何移动,玩家都能安全到达宝藏。
核心思路
1. 逆向思维
不是找一条具体路径,而是找出所有"安全位置":
- 如果玩家在某个位置
(x,y)
,海盗在k
步内能到达该位置的同一行或同一列的某个点,那么玩家在这个位置不安全 - 否则,这个位置是安全的
2. 安全条件判断
对于位置
(x,y)
,检查四个方向:- 向左:检查
(x,y-1)
,(x,y-2)
... 直到遇到陆地或边界 - 向右:检查
(x,y+1)
,(x,y+2)
... 直到遇到陆地或边界 - 向上:检查
(x-1,y)
,(x-2,y)
... 直到遇到陆地或边界 - 向下:检查
(x+1,y)
,(x+2,y)
... 直到遇到陆地或边界
如果任意方向上存在一个点,海盗能在
k
步内到达(k
是玩家到达(x,y)
的步数),那么这个位置不安全。3. 算法步骤
- BFS计算海盗到所有点的最短距离
d[i][j]
- BFS计算玩家安全路径:
- 从起点开始扩展
- 对于每个候选位置,检查是否安全(调用
check
函数) - 如果安全且未访问过,加入队列
- 如果到达宝藏点,返回
YES
代码详解
数据结构
int d[N][N]; // 海盗到各点的最短距离 int D[N][N]; // 玩家到各点的步数 bool a[N][N]; // 是否是陆地 char s[N][N]; // 地图
第一步:海盗BFS
void bfs(int x, int y) { // 标准BFS,计算海盗起点到所有可达点的最短距离 // 陆地不可达,距离为inf }
第二步:安全检查函数
bool check(int x, int y, int k) { // 检查位置(x,y)在玩家第k步到达时是否安全 // 检查水平方向 for (左右两个方向) { 沿着该方向扫描,直到遇到陆地或边界 如果该方向上某个点的d[xx][yy] <= k,说明不安全 } // 检查垂直方向(同理) return 是否找到威胁点; }
第三步:玩家安全BFS
bool Dfs(int x, int y) { // 从玩家起点开始BFS // 对于每个邻居位置(xx,yy): // 如果该位置未被访问 且 安全检查通过 // 则加入队列 // 如果到达宝藏,返回true }
关键逻辑分析
为什么这样检查是充分的?
因为海盗的威胁范围是整行整列(无陆地阻挡):
- 如果海盗能在
k
步内到达玩家所在行/列的某个点 - 那么无论玩家怎么走,海盗都能在
k
回合内与玩家处于同一行/列 - 玩家就失败了
时间复杂度
- 两次BFS:
O(N*M)
- 安全检查:最坏
O(N+M)
,但实际运行很快 - 总复杂度:
O(N*M*(N+M))
,对于N,M ≤ 700
需要优化
优化思路
代码中注释掉的部分是一种优化:
// 预处理每行/每列的最小海盗距离 // 这样check时可以O(1)判断
样例验证
样例1
Y.....V ..I.... ..IIIII ....... ...T...
输出:
YES
- 玩家可以绕开海盗的视线范围到达宝藏
样例2
Y....V. ..I.... ..IIIII ....... ...T...
输出:
NO
- 海盗初始位置使得玩家无法安全到达宝藏
总结
这道题的核心是:
- 博弈思维:考虑最坏情况下的海盗移动
- 安全区域分析:基于距离和视线判断安全性
- BFS应用:分别计算海盗威胁范围和玩家安全路径
通过预处理海盗距离 + 动态检查安全条件,可以高效解决这个复杂的博弈路径问题。
- 地图是
- 1
信息
- ID
- 3356
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者