题目传送门

先警示后人:

我在看题目的时候看成了 \(1 \le r,c \le 4000\)

然后被迫想了一个 \(\operatorname{O}(\operatorname{RC} \ \operatorname{log} \ \operatorname{RC})\) 发现好像有点玄

最后乱加一堆优化跑爆了只能重写


正解:

  • 对于这个数组考虑 二维 转 一维 ,静态数组存不下

    如果喜欢用动态二维数组自然是很好的()
  • 算法上考虑两遍 BFS 直接秒了,下面开始介绍思路

第一遍 BFS:

我们多源 BFS 对所有 R 进行扩展

更新图上每个点最早被烟雾覆盖的时间 \(\operatorname{time[\ ]}\)

BFS 的特性可以保证这样遍历到的每个点确实是正确的

\(\operatorname{O(RC)}\)

第二遍 BFS:

从 A 开始或从 K 开始都无所谓,我喜欢反图就从 K 开始了

  • 我们的目标:

    找到所有合法路径(即能从 A 到达 K 的路径)最晚被烟雾碰到的那条路,并且求出这条路上最小的 \(\operatorname{time[\ ]}\)

  • 实现方式:

    从 K 开始遍历四个方向

    如果找到了边界,就 break

    如果找到了 o ,说明找到一条子路了,就判断当前子路存的 path_time[ ] 是否小于当前手里搜出来的最小断点,如果是,就拿手里这个更新这个子路的 path_time[ ]

    如果找到了 A ,说明走通了一条合法路径,我们拿手里的最小断点直接去 \(\max(\operatorname{ans,current})\)

    而这个 BFS 的队列的存储要使用大根堆的优先队列来尽可能的贪心,就像 dijkstra 选取最小边来扩展

    我们从队列里面拿出任意一个点的时候,将他的最早断点与此时的 ans 对比,如果这个最早断点早于 ans ,那么直接可以 continue

    这时 \(\operatorname{O(RC \ log \ RC)}\)

  • 正确性简证:

    激光不经过任何烟雾,从而攻击到国王。

    也就是所有 A 到 K 的合法路径上都存在烟雾,求这个最早的时间

    转换成不以时间为变量,求所有路径上最早断点最晚的路径,当这个路径被遮住是,其他所有路径也早就被遮住

细节都在代码里了

注释清晰,码风优良


\(\mathbb {\LARGE C \large _O \ \Large ^D \normalsize _E}\)

#include<bits/stdc++.h>

using namespace std;

const int N = 4002;
const int dx[5] = {0, 1, -1, 0, 0};
const int dy[5] = {0, 0, 0, 1, -1}; struct SMOKE {
int x, y;
}; queue< SMOKE >R;//存储R的坐标,用于多源BFS预处理图 int r, c, in_x, in_y, pth_min;//in_x,in_y存国王的坐标
int a[N << 4], SMoke_TIme[N << 4], vis[N << 4]; //a存图; SMoke_TIme存烟雾的时间层; vis存当前点(只有镜子才会有)的最早断点
int ans = 0;
int x , y, xx, yy, v; void input(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin >> r>> c;
for(int i = 1; i <= r; i++){
for(int j = 1; j <= c; j++){
SMoke_TIme[c * (i - 1) + j] = -1;
char ch;
cin >> ch;
if(ch == 'o') a[c * (i - 1) + j] = 4;
if(ch == '.') a[c * (i - 1) + j] = 0;
if(ch == 'A') a[c * (i - 1) + j] = 1;
if(ch == 'K') {
a[c * (i - 1) + j] = 2;
in_x = i;
in_y = j;//存储国王位置
}
if(ch == 'R') {
a[c * (i - 1) + j] = 3;
R.push(SMOKE{i, j});//烟雾初始位置入队保存
SMoke_TIme[c * (i - 1) + j] = 0;
}
}
}
} void output(){
cout << ans << endl;
} void BFS(){//多源BFS预处理图的时间层 while( !R.empty()){
x = R.front().x;
y = R.front().y;
R.pop();
for(int i = 1; i <= 4; i++){//四个方向扩散
xx = x + dx[i];
yy = y + dy[i];
if(xx < 1 or yy < 1 or xx > r or yy > c or SMoke_TIme[c * (xx - 1) + yy] != -1)continue;//边界条件
//BFS能保证每个点搜到的时候都是距离他最近的烟雾为祖先
//也就是能保证SMoke_TIme最小
SMoke_TIme[c * (xx - 1) + yy] = SMoke_TIme[c * (x - 1) + y] + 1;//是自己祖先的下一秒
R.push(SMOKE{xx, yy});
}
}
} struct path{
int x, y;
int v;//到这个镜子的这条路径上的最早阻断点,也就是这条路最早失效的时间
bool operator <(const path &other)const {
return v >= other.v;//优先队列取出当前最优解(就是最晚被干掉的合法路径)
}
}; priority_queue< path >q; void solve_BFS(){//从国王位置倒着搜所有合法路径 for(int i = 1; i <= 4; i++){
xx = in_x;
yy = in_y;
pth_min = SMoke_TIme[c * (xx - 1) + yy];
while(true){
xx += dx[i];
yy += dy[i];
if(xx < 1 or yy < 1 or xx > r or yy > c)break;//边界条件判断 if(a[c * (xx - 1) + yy] == 3) break;//剪枝 pth_min = min(pth_min, SMoke_TIme[c * (xx - 1) + yy]); if(a[c * (xx - 1) + yy] == 4){//遇到镜子就停止这个方向的初始化
vis[c * (xx - 1) + yy] = max(vis[c * (xx - 1) + yy], pth_min);
q.push(path{xx, yy, pth_min});
break;
}
if(a[c * (xx - 1) + yy] == 1){//遇到A就说明可以直接返回这条路线了
ans = max(ans, pth_min);
break;
}
}
} while(!q.empty()){
path t = q.top();
q.pop();
if(t.v <= ans)continue;//剪枝优化:当前这条路径已经废了,被阻挡的时间比我们已经求出来的还早
for(int i = 1; i <= 4; i++){
xx = t.x;
yy = t.y;
pth_min = t.v;
while(true){
xx += dx[i];
yy += dy[i];
if(xx < 1 or yy < 1 or xx > r or yy > c) break;//边界条件判断 if(a[c * (xx - 1) + yy] == 3)break;//剪枝 pth_min = min(pth_min, SMoke_TIme[c * (xx - 1) + yy]);//更新路径 if(a[c * (xx - 1) + yy] == 4){
if(pth_min > vis[c * (xx - 1) + yy]){//如果是更好的子路
vis[c * (xx - 1) + yy] = pth_min;
q.push(path{xx, yy, pth_min});
}
break;
} if(a[c * (xx - 1) + yy] == 1){//合法路径直接返回
ans = max(pth_min, ans);
break;
}
}
}
}
} main(void){
input(); BFS(); solve_BFS(); output();
}

题解:P14065 [PO Final 2022] 对弈 / Laserschack的更多相关文章

  1. 题解 [JOI 2019 Final] 独特的城市

    题面 解析 首先有一个结论, 对一个点\(x\)有贡献的城市 肯定在它到离它较远的直径的端点的链上. 假设离它较远的端点是\(S\), 如果有一个点\(u\)不在\(x\)到\(S\)的链上, 却对\ ...

  2. 题解 [JOI 2019 Final] 硬币收藏

    题面 解析 首先题目可以理解为把一些点放进一个框里,每个格子只能放一个. 那么显然你可以先把这个点移到框里离它最近的格子里, (这个时候格子里可以放很多个) 然后再在框里乱跑移动. 那么我们先考虑只有 ...

  3. [题解] Codeforces Dytechlab Cup 2022 1737 A B C D E 题解

    傻*Dytechlab还我rating!(不过目前rating还没加上去,据说E是偷的说不定要unrated) 实在没预料到会打成这样... 求点赞 点我看题 A. Ela Sorting Books ...

  4. Java数据库表自动转化为PO对象

    本程序简单实现了数据库内省,生成PO对象. 数据库内省有如下两种实现方式: 通过mysql元表 通过desc table,show tables等命令 import java.io.IOExcepti ...

  5. PO Release Final Closed 灾难恢复

    今天不小心 Final Closed了一条Po Release,只能通过后台更新数据恢复了. 更新后可接收可匹配,但不保证更新数据有遗漏,慎用. 更新前备份各表数据 UPDATE PO_LINE_LO ...

  6. 【题解】LOJ2759. 「JOI 2014 Final」飞天鼠(最短路)

    [题解]LOJ2759. 「JOI 2014 Final」飞天鼠(最短路) 考虑最终答案的构成,一定是由很多飞行+一些上升+一些下降构成. 由于在任何一个点上升或者下降代价是一样的,所以: 对于上升操 ...

  7. Lyft Level 5 Challenge 2018 - Final Round (Open Div. 2) (前三题题解)

    这场比赛好毒瘤哇,看第四题好像是中国人出的,怕不是dllxl出的. 第四道什么鬼,互动题不说,花了四十五分钟看懂题目,都想砸电脑了.然后发现不会,互动题从来没做过. 不过这次新号上蓝名了(我才不告诉你 ...

  8. Google kickstart 2022 Round A题解

    Speed Typing 题意概述 给出两个字符串I和P,问能否通过删除P中若干个字符得到I?如果能的话,需要删除字符的个数是多少? 数据规模 \[1≤|I|,|P|≤10^5 \] 双指针 设置两个 ...

  9. PKUSC 2022 口胡题解

    \(PKUSC\ 2022\)口胡题解 为了更好的在考试中拿分,我准备学习基础日麻知识(为什么每年都考麻将 啊啊啊) 首先\(STO\)吉老师\(ORZ,\)真的学到了好多 观察标签发现,这套题覆盖知 ...

  10. JOI 2018 Final 题解

    题目列表:https://loj.ac/problems/search?keyword=JOI+2018+Final T1 寒冬暖炉 贪心 暴力考虑每相邻两个人之间的间隔,从小到大选取即可 #incl ...

随机推荐

  1. vscode linux c++ 配置

    简介 最官方的配置方案 https://code.visualstudio.com/docs/cpp/config-linux 有三个文件会生成 tasks.json (编译器构建设置) launch ...

  2. 一文彻底搞懂javascript中的undefined

    undefined in javascript undefined是可以说是javascript中最特殊的一个类型,许多其他语言中都没有这个类型.它表示一个变量已经声明,但还没有被赋值. let a; ...

  3. 使用Semantic Kernel实现Claude Code的Agents TODO能力

    使用Semantic Kernel实现Claude Code的Agents TODO能力 引言 在现代软件开发中,AI辅助编程工具正在成为开发者不可或缺的伙伴.Claude Code作为Anthrop ...

  4. ps正版弹窗问题解决

  5. 文人的激情和诗人的写意敲出来的UI 框架-Layui

    https://www.ilayuis.com/ 由职业前端倾情打造,面向全层次的前后端开发者,易上手开源免费的 Web UI 组件库 返璞归真 身处在前端社区的繁荣之下,我们都在有意或无意地追逐.而 ...

  6. Browser-Use在UI自动化测试中的应用

      一. Browser-Use简介 Browser-Use是一个开源可以操控浏览器的Python库,使用者能够通过LLM与浏览器自动化操作结合起来.这个库支持自然语言描述自动化测试任务或者定义AI ...

  7. win10 阻止任务栏图标闪烁

    Win + R 输入 regedit 打开注册表编辑器; 打开路径 "计算机\HKEY_CURRENT_USER\Control Panel\Desktop"; 右侧双击 Fore ...

  8. 为什么RAG技术可以缓解大模型知识固话和幻觉问题

    1.大模型知识固化和幻觉问题 要理解大模型的时效性问题,需首先明确其技术原理:大模型通过输入文本与已固化在神经网络中的知识进行匹配,预测并输出概率最大的文本内容作为答案.其固化知识的神经网络形成于前期 ...

  9. Java面向对象基础——10.内部类

    目录 Java内部类总结 1. 内部类(Inner Class) 2. 匿名类(Anonymous Class) 3. 静态内部类(Static Nested Class) 共性与差异 Java内部类 ...

  10. 解決 VMware Workstation 与 Device/Credential Guard 不相容,无法启动虚拟机的问题

    问题: 打开 VMware Workstation 准备运行虚拟机时,报错如下图 原因: Windows 系統的 Hyper-V 不相容导致 解决方案: 通過命令关闭 Hyper-V(控制面板关闭 H ...