NOI Online #2 普及组 第二题:荆轲刺秦王

  • 前言
  • 题目
  • 解析
  • 完整代码

前言

做题之前,让我们大吼几声:

你 这 个 “ 良 心 ” 出 题 人 ! \bold{\sout{你这个“良心”出题人!}} 你这个“良心”出题人!

害的我这道题爆零! \bold{\Large\xcancel\text{害的我这道题爆零!}} 害的我这道题爆零!

吼完了,我们来看看这道题怎么做?

题目

传送门

解析

一看题目,像个搜索

再一看,像个广度优先搜索

既然是BFS,那我们首先要搞出一个(一堆)队列

那问题是队列里咱们存啥呢???

首先,按照广搜解决“迷宫问题”的国际惯例,肯定要先把坐标和步数存到里面!

可是,这似乎不大够?

荆轲还有两种技能:隐身和瞬移。
1.隐身:balabala……
2.瞬移:balabala……
现在给出咸阳城的地图,请计算荆轲到达秦王所在点所需的最短时间。此外,在所用时间相同情况下,荆轲希望使用的两种技能总次数尽可能少;在所用时间与技能次数相同情况下,荆轲希望使用的隐身次数尽可能少。

emmmmm,还要把隐身和瞬移的使用次数存下来~

啊,要存这么多东西……这时候,结构体就要派上用场啦!

struct Node{int x;int y;int yx;int sy;int sum;
};
queue<Node> q;

当然,我们要在茫茫多的方案中选择一个最优解——所以,我们要写一个函数(算是取min吧……),来选择一个最优解

Node Check_Ans(Node a,Node b)
{if(a.sum!=b.sum)return a.sum<b.sum?a:b;if(a.yx+a.sy!=b.yx+b.sy)return a.yx+a.sy<b.yx+b.sy?a:b;return a.yx<b.yx?a:b;
}

所有结构体啥的准备工作都已经完成啦!接下来,咱们考虑一下main函数的框架:包括输入等细节的处理

especially,咱们来康康要输入要注意啥:

输入的整个地图,既有诸如 S T . 之类的字符,还有表示卫兵监控范围的数,两个这么一整合——就用string来输入吧!
由于S啊,T啊啥的随便换个数就行了,只要能标记上就OK,而地图上的数字是非常重要的,所以地图我们用int类型存储
这应该也是每个字符串模拟题要注意的地方,当输入到字符串里的数字 ≥ 10 \ge10 ≥10 的时候,我们要一位一位加上去,(写的时候可以照快读那样写),千万不要读完一位剩下的就不管了
于每种字符的特殊处理——标记起点和终点,遇到卫兵时,我们要处理出卫兵的观察范围

呼呼,大概就这么多啦~

ios::sync_with_stdio(false);cin>>n>>m>>c1>>c2>>d;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){string s;cin>>s;if(s[0]=='S'){sx=i,sy=j;mp[i][j]=-1;q.push((Node){sx,sy,0,0,0});vis[i][j][0][0]=1;}else if(s[0]=='T'){ex=i,ey=j;mp[i][j]=-2;}else if(s[0]=='.')mp[i][j]=0;else{int x=0;for(int i=0;i<s.size();i++)x=(x<<1)+(x<<3)+(s[i]^'0');mp[i][j]=x;pre_look(i,j,x-1); //处理士兵观察范围}}}for(int i=1;i<=n;i++){int sum=0;for(int j=1;j<=m;j++){sum+=tag[i][j];if(sum>0)look[i][j]=1; }}bfs();if(ans.sum==233333333) puts("-1");else{printf("%d %d %d",ans.sum,ans.yx,ans.sy);}

⋆ 划重点了! \Huge\color{red}\star\color{black}\text{\huge 划重点了!} ⋆划重点了!

那接下来的问题来啦!如何处理每个士兵的监控范围呢?

暴力枚举?TLE警告

时间复杂度 O ( a 2 ) O(a^2) O(a2) ,加上输入的循环 O ( a 2 m n ) O(a^2mn) O(a2mn) ,TLE警告……

那咋办呢?别急,咱们先画个图!

下图就是 a = 3 a=3 a=3 的情况,士兵可以观察到和它的曼哈顿距离 ≤ 2 \le2 ≤2 的点


(图中, 黑色 \bold{\text{黑色}} 黑色 点为士兵所在点, 紫色 \bold{\color{purple}\text{紫色}} 紫色点为士兵的监控范围点)

我们惊奇地发现,覆盖区域是一个实心的菱形!

也就是说,士兵观察到的范围,对每一行/列来说,都是一段连续的区间! 处理范围,是一个区间修改问题!

提到区间修改,大家会想到什么呢?

线段树?……树状数组?……差分!

众所周知,差分在区间修改问题中有奇效,原因是它只需要改——两个点, 我们只需要在左端点的位置 + 1 +1 +1 ,右端点 + 1 +1 +1 的位置 − 1 -1 −1。

而且,既然区域是个菱形,我们可别忘了菱形的对称性,也就是说,我们找到一个点之后,我们可以根据它的两条对称轴找到它的三个对应点

也就是说,我们能在 O ( a ) O(a) O(a) 的时间内求出一个士兵的监控范围,处理这一块的总复杂度为 O ( a m n ) O(amn) O(amn) ,不错不错~

我这里采用的是从中心向四周扩展的方式——也就是说枚举当前点到中心的距离进行修改


(图中, 绿色 \bold{\color{green}\text{绿色}} 绿色 点为修改的左端点, 橙色 \bold{\color{orange}\text{橙色}} 橙色 点为修改的右端点,为了符合我们OIer的坐标书写习惯, xxx 轴正方向为下方, yyy 轴正方向为右方)

结合着这个图,你就可以理解下方的代码惹~

void pre_look(int x,int y,int k)
{for(int i=0;i<=k;i++){tag[max(x-i,1)][max(y-(k-i),1)]++; tag[max(x-i,1)][min(y+(k-i),m)+1]--;tag[min(x+i,n)][max(y-(k-i),1)]++;tag[min(x+i,n)][min(y+(k-i),m)+1]--;}
}

bfs:

void bfs(){while(!q.empty()){Node fr=q.front();q.pop();if(fr.sum>ans.sum)continue;if(fr.x==ex&&fr.y==ey){ans=Check_Ans(ans,fr);continue;} for(int i=0;i<8;i++){int nx=fr.x+dx[i];int ny=fr.y+dy[i];if(nx<1||nx>n||ny<1||ny>m||mp[nx][ny]>0)continue;if(look[nx][ny]){if(vis[nx][ny][fr.yx+1][fr.sy]||fr.yx+1>c1)continue;vis[nx][ny][fr.yx+1][fr.sy]=1;q.push((Node){nx,ny,fr.yx+1,fr.sy,fr.sum+1});}else{if(vis[nx][ny][fr.yx][fr.sy])continue;vis[nx][ny][fr.yx][fr.sy]=1;q.push((Node){nx,ny,fr.yx,fr.sy,fr.sum+1});             }}if(fr.sy+1>c2)continue;for(int i=0;i<4;i++){int nx=fr.x+dx[i]*d;int ny=fr.y+dy[i]*d;if(nx<1||nx>n||ny<1||ny>m||mp[nx][ny]>0)continue;if(look[nx][ny]){if(vis[nx][ny][fr.yx+1][fr.sy+1]||fr.yx+1>c1)continue;vis[nx][ny][fr.yx+1][fr.sy+1]=1;q.push((Node){nx,ny,fr.yx+1,fr.sy+1,fr.sum+1});}else{if(vis[nx][ny][fr.yx][fr.sy+1])continue;vis[nx][ny][fr.yx][fr.sy+1]=1;q.push((Node){nx,ny,fr.yx,fr.sy+1,fr.sum+1});                }           }}
}

完整代码

#include<bits/stdc++.h>
using namespace std;
struct Node{int x;int y;int yx;int sy;int sum;
};
Node Check_Ans(Node a,Node b)
{if(a.sum!=b.sum)return a.sum<b.sum?a:b;if(a.yx+a.sy!=b.yx+b.sy)return a.yx+a.sy<b.yx+b.sy?a:b;return a.yx<b.yx?a:b;
}
bool vis[355][355][20][20],look[355][355];
int tag[355][355];
int n,m,c1,c2,d;
int mp[355][355];
const int dx[8]={1,0,-1,0,1,-1,-1,1},dy[8]={0,1,0,-1,1,1,-1,-1};
void pre_look(int x,int y,int k)
{for(int i=0;i<=k;i++){tag[max(x-i,1)][max(y-(k-i),1)]++; tag[max(x-i,1)][min(y+(k-i),m)+1]--;tag[min(x+i,n)][max(y-(k-i),1)]++;tag[min(x+i,n)][min(y+(k-i),m)+1]--;}
}
int sx,sy,ex,ey;
queue<Node> q;
Node ans=(Node){0,0,233333333,233333333,233333333};
void bfs(){while(!q.empty()){Node fr=q.front();q.pop();if(fr.sum>ans.sum)continue;if(fr.x==ex&&fr.y==ey){ans=Check_Ans(ans,fr);continue;} for(int i=0;i<8;i++){int nx=fr.x+dx[i];int ny=fr.y+dy[i];if(nx<1||nx>n||ny<1||ny>m||mp[nx][ny]>0)continue;if(look[nx][ny]){if(vis[nx][ny][fr.yx+1][fr.sy]||fr.yx+1>c1)continue;vis[nx][ny][fr.yx+1][fr.sy]=1;q.push((Node){nx,ny,fr.yx+1,fr.sy,fr.sum+1});}else{if(vis[nx][ny][fr.yx][fr.sy])continue;vis[nx][ny][fr.yx][fr.sy]=1;q.push((Node){nx,ny,fr.yx,fr.sy,fr.sum+1});                }}if(fr.sy+1>c2)continue;for(int i=0;i<4;i++){int nx=fr.x+dx[i]*d;int ny=fr.y+dy[i]*d;if(nx<1||nx>n||ny<1||ny>m||mp[nx][ny]>0)continue;if(look[nx][ny]){if(vis[nx][ny][fr.yx+1][fr.sy+1]||fr.yx+1>c1)continue;vis[nx][ny][fr.yx+1][fr.sy+1]=1;q.push((Node){nx,ny,fr.yx+1,fr.sy+1,fr.sum+1});}else{if(vis[nx][ny][fr.yx][fr.sy+1])continue;vis[nx][ny][fr.yx][fr.sy+1]=1;q.push((Node){nx,ny,fr.yx,fr.sy+1,fr.sum+1});                }           }}
}
int main()
{ios::sync_with_stdio(false);cin>>n>>m>>c1>>c2>>d;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){string s;cin>>s;if(s[0]=='S'){sx=i,sy=j;mp[i][j]=-1;q.push((Node){sx,sy,0,0,0});vis[i][j][0][0]=1;}else if(s[0]=='T'){ex=i,ey=j;mp[i][j]=-2;}else if(s[0]=='.')mp[i][j]=0;else{int x=0;for(int i=0;i<s.size();i++)x=(x<<1)+(x<<3)+(s[i]^'0');mp[i][j]=x;pre_look(i,j,x-1);}}}for(int i=1;i<=n;i++){int sum=0;for(int j=1;j<=m;j++){sum+=tag[i][j];if(sum>0)look[i][j]=1;  }}bfs();if(ans.sum==233333333) puts("-1");else{printf("%d %d %d",ans.sum,ans.yx,ans.sy);}return 0;
}

NOI Online #2 普及组 第二题:荆轲刺秦王相关推荐

  1. NOIP1996复赛 普及组 第二题 python

    http://noi.openjudge.cn/ch0108/02/ """ NOIP1996复赛 普及组 第二题 python1.8编程基础之多维数组 02 同行列对角 ...

  2. NOIP 2002 普及组第二题

    [NOIP2002 普及组] 选数 题目描述 已知 n 个整数 x1,x2,x3,xn,以及 1 个整数 k(k<n).从 n 个整数中任选 k个整数相加,可分别得到一系列的和.例如当 n=4, ...

  3. 【ybtoj】【BFS】【例题4】荆轲刺秦王

    [例题4]荆轲刺秦王 Link 解题思路 Code Link 传送门 题目 解题思路 wcnmd,我就无语了,搞了我一天的题,就nm数组开小了,wcnm 守卫监视范围 差分:但我不会,这题数据太淼,直 ...

  4. 荆轲刺秦王--咸阳巧遇(剧本)

    荆轲刺秦王 咸阳巧遇 左丰.杨庆华等 1 (咸阳城,蒙骜交警模样,吹着口哨,挥舞着红绿旗,指挥着交通.) 蒙骜:咳咳,你,走路不看旗子!你这匹马,逆向行驶,知道吗?跟你们讲过多少遍了......要不怎 ...

  5. 【ybtoj 高效进阶 1.5】【广搜】 荆轲刺秦王

    [ybtoj 高效进阶 1.5][广搜] 荆轲刺秦王 解题思路 预处理 士兵的监测范围可以用查分做 例,士兵监测范围是3,如图 在每一行能被看到的起点+1,看不到的第一个-1 最后用前缀和求出所有范围 ...

  6. 【ybtoj】荆轲刺秦王

    荆轲刺秦王 题目描述 输入格式 第一行五个整数n,m,c1,c2,dn,m,c_1,c_2,dn,m,c1​,c2​,d,代表地图的大小为n*m隐身的使用限制次数为c1c_1c1​,瞬移的使用次数为c ...

  7. 洛谷6474[NOI Online #2 入门组]荆轲刺秦王

    题目背景 本测试数据为脚造,欢迎提供hack. 第18组数据卡了很多人,放于附件中供检查. 题目描述 时隔数年,刺客荆轲再次来到咸阳宫,试图刺杀嬴政. 咸阳宫的地图可以描述为一个 n 行 m 列的矩形 ...

  8. 洛谷P6474荆轲刺秦王

    传送门 upd on 2022.8.17:时隔半年复盘,把标记改成了差分写法,使用了STL队列,进行了码风优化.(为什么当年博客风格如此智障/kk 谁能拒绝一只拥有无CD闪现和大招的荆轲呢. 小明首先 ...

  9. 图书管理员【2017年普及组第二题】

    图书管理员图书管理员图书管理员 题目描述 图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个正整数. 每位借书的读者手中有一个需求码,这个需求码也是一个正整数.如果一本书的图书编 ...

最新文章

  1. 推荐一款 Flutter Push 推送功能插件
  2. 走向.NET架构设计—第三章—分层设计,初涉架构
  3. 航空频率表 2020_航空波段+调频、中波、短波,这个美国TR608收音机值40美元吗?...
  4. dynamic和var的区别
  5. PHP访问MySQL数据库
  6. windows查看文件MD5值
  7. 手机屏坏了怎么把里面存东西取出来_手机又卡了,到底是运行不够还是存储容量不足?1分钟搞懂...
  8. 表格数字乘以百分比怎么算_Excel输入多位数字之后有了“E”,用文本格式一步到位,恢复原状...
  9. 错误: 代理抛出异常错误: java.rmi.server.ExportException: Port already in use: 1099; nested exception is
  10. [MySQL] InnoDB三大特性之 - 插入缓冲
  11. jms两种模式例子-超越昨天的自己系列(2)
  12. rstudio 连接mysql_Rstudio ODBC 连接MySQL
  13. 如何在Ubuntu上安装Couch DB 1.5
  14. 【U3D实战笔记】2DProject:RushMan
  15. Web移动端Fixed布局的解决方案(原文出处:http://efe.baidu.com/blog/mobile-fixed-layout)
  16. 2023届暑期实习华为面试手撕题
  17. Ajax跨域请求(一):什么是CORS
  18. docker部署博客项目
  19. 清华大学 陈晨 计算机,TNet基于树型结构集群工具软件通信协议.PDF
  20. kubeadm修改默认证书有效期,解决证书过期问题

热门文章

  1. 乐视2 pro2 IMAX手机root权限 刷rece 解锁 刷系统等
  2. 使用printf语句输出名言:“贵有恒,何必三更起五更睡:最无益,只怕一日曝十日寒。“
  3. 计算机共享文件误删怎么恢复,在电脑上不小心把共享里的EXCEL表格数据给删除了,该怎么恢复这个文件的数据啊?,excel表格里误删数据恢复...
  4. Honey Badger BFT(异步共识算法)笔记
  5. Windows Sever 2008 本地安全策略之登陆策略
  6. HTTP常见状态码 200 301 302 404 500
  7. 清除linux系统盘空间,linux磁盘空间不足怎么办,磁盘清理方法
  8. 东方通TongWeb部署
  9. 计算机基础知识对程序员来说有多重要?
  10. window7调用计算机,教你查看win7系统电脑使用记录的具体方法