扫雷


题目描述:

小明最近迷上了一款名为《扫雷》的游戏。

其中有一个关卡的任务如下:

在一个二维平面上放置着 n 个炸雷,第 i 个炸雷 (x\(_i\),y\(_i\),r\(_i\)) 表示在坐标 (x\(_i\),y\(_i\)) 处存在一个炸雷,它的爆炸范围是以半径为 r\(_i\) 的一个圆。

为了顺利通过这片土地,需要玩家进行排雷。

玩家可以发射 m 个排雷火箭,小明已经规划好了每个排雷火箭的发射方向,第 j 个排雷火箭 (x\(_j\),y\(_j\),r\(_j\)) 表示这个排雷火箭将会在 (x\(_j\),y\(_j\)) 处爆炸,它的爆炸范围是以半径为 r\(_j\) 的一个圆,在其爆炸范围内的炸雷会被引爆。

同时,当炸雷被引爆时,在其爆炸范围内的炸雷也会被引爆。

现在小明想知道他这次共引爆了几颗炸雷?

你可以把炸雷和排雷火箭都视为平面上的一个点。

一个点处可以存在多个炸雷和排雷火箭。

当炸雷位于爆炸范围的边界上时也会被引爆。

解题思路:

  1. 暴力扫描所有可能爆炸的点:

    无疑啊,这种暴力的复杂度在O(n\(^2\))的,0<=n<=5e4,肯定会TLE滴

考虑到半径0<=r<=10,所以我们考虑能不能只扫描炸弹半径内可能会被引爆的点,那复杂度就会被降下来

  1. 哈希+bfs:

    我们将所有的炸弹用哈希映射到到一个唯一的哈希值然后在bfs的过程中,扫描当前炸弹的半径中是否存在炸弹(哈希查找),这样的总复杂度就在O(2r\(^2\)n+2r\(^2\)m)

    其中:bfs(O(n)),哈希(O(1))

哈希:map<key,val>

考虑哈希的细节:

  1. 二维坐标x,y唯一映射的哈希值:

    由于x,y的范围为[0,1e9],所以我们可以将x,y唯一的映射到一个哈希值(x*mod+y),mod = 1e9+1

    这就是将x,y映射为一个1e9+1进制的数,假设这个哈希值为h,那x = h/mod,y = h%mod
  2. 哈希表的长度:已知题目n小于等于5e4,哈希表的长度至少是2n,尽可能的开大空间,避免冲突的发生,同时哈希表的长度应该为一个质数,所以取1e6+7
  3. 哈希表的key:获取哈希值之后需要将其存入哈希表的一个位置,这个位置就是该哈希值的key。对长度取模即可,若冲突则后移。

代码实现:

# include<bits/stdc++.h>
using namespace std;
# define int long long
const int N = 5e4+10,M = 1e6+7,mod = 1e9+7;
int h[M];//哈希表
int id[M];//对应哈希key的炸弹下标
bool vis[N];//是否被引爆过
struct node{
int x,y,r;
}a[N];
int n,m; /*
哈希:map<key,value>
*/
int get_hs(int x,int y)//获取哈希值
{
return (int)x*mod+y;
}
int find(int x,int y)//获取哈希的key
{
int hs = get_hs(x,y);
int key = (hs%M+M)%M; while(h[key] != -1&&h[key] != hs)//如果冲突就后移
{
key++;
if(key == M) key = 0;
}
return key;
} bool check(int x,int y,int r,int a,int b)//是否会被引爆
{
int d = (x-a)*(x-a)+(y-b)*(y-b);
return d<=r*r;
} void bfs(int pos){
queue<int> q;
q.push(pos);
vis[pos] = 1;
while(q.size()){
int t = q.front();
q.pop();
int x = a[t].x,y = a[t].y,r = a[t].r;
/*
扫描整个半径内是否存在会被引爆的炸弹
*/
for(int xx = max(x-r,0ll);xx<=min(x+r,(int)1e9);++xx){
for(int yy = max(y-r,0ll);yy<=min(y+r,(int)1e9);++yy){
int key = find(xx,yy);
if(id[key]&&!vis[id[key]]&&check(x,y,r,xx,yy)){
int pos = id[key];
vis[pos] = 1;
q.push(pos);
}
}
}
}
} signed main(){
cin>>n>>m;
memset(h,-1,sizeof h);
int x,y,r;
for(int i = 1;i <= n;++i){
cin>>x>>y>>r;
a[i] ={x,y,r};
int key = find(x,y);//获取key
if(h[key] == -1) h[key] = get_hs(x,y);//存储哈希值 if(!id[key]||a[id[key]].r<r)//如果该点有炸弹,或者有一个半径更大的炸弹
{
id[key] = i;
}
} for(int i = 1;i <= m;++i){
cin>>x>>y>>r; // 扫描整个半径内是否存在会被引爆的炸弹 for(int xx = max(x-r,0ll);xx<=min(x+r,(int)1e9);++xx){
for(int yy = max(y-r,0ll);yy<=min(y+r,(int)1e9);++yy){
int key = find(xx,yy);
//是否有炸弹,是否被引爆过,是否能被引爆
if(id[key]&&!vis[id[key]]&&check(x,y,r,xx,yy)){
bfs(id[key]);
}
}
}
}
int ans = 0;
//扫描答案
for(int i = 1;i <= n;++i){
int key = find(a[i].x,a[i].y);
int pos = id[key];
if(pos&&vis[pos]) ans++;
}
cout<<ans<<endl; return 0;
}

扫雷(哈希+bfs)的更多相关文章

  1. 哈希+Bfs【P2730】 魔板 Magic Squares

    没看过题的童鞋请去看一下题-->P2730 魔板 Magic Squares 不了解康托展开的请来这里-->我这里 至于这题为什么可以用康托展开?(瞎说时间到. 因为只有8个数字,且只有1 ...

  2. 山东省第四届ACM省赛

    排名:http://acm.sdut.edu.cn/sd2012/2013.htm 解题报告:http://www.tuicool.com/articles/FnEZJb A.Rescue The P ...

  3. poj 2432 Around the world bfs+哈希

    由于每个点的状态包含走过来的距离,所以要存二维的状态,但是状态总量太多,所以可以用哈希来搞. 那么就是bfs最短路,哈希记录状态了. #include <iostream> #includ ...

  4. Eight(bfs+全排列的哈希函数)

    Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22207   Accepted: 9846   Special Judge ...

  5. UVA 10651 Pebble Solitaire(bfs + 哈希判重(记忆化搜索?))

    Problem A Pebble Solitaire Input: standard input Output: standard output Time Limit: 1 second Pebble ...

  6. hdu1067-Gap(bfs+哈希)

    Let's play a card game called Gap. You have 28 cards labeled with two-digit numbers. The first digit ...

  7. Poj2946-The Warehouse(bfs+哈希)

    题目我就不粘贴了... 题意:给出地图,最大8*8,出口用'E'表示,空地用'.'表示,数字表示此处有多少个箱子,主人公的起点应该是在有箱子的地方,他可以朝四个方向移动,但是只有两种方式 一种是他移动 ...

  8. 【算法】BFS+哈希解决八数码问题

    15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...

  9. POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)

    Description Let's play a puzzle using eight cubes placed on a 3 × 3 board leaving one empty square. ...

随机推荐

  1. mybatisplus-ActiveRecord 模式

    ActiveRecord 模式 直接调用Model对象来进行增删改查. 实体类只需继承 Model 类即可进行强大的 CRUD 操作 需要项目中已注入对应实体的BaseMapper 实体类User 点 ...

  2. Java中字节流的总结及代码练习

    Java中的字节流 在描述字节流时,先知道什么是流 流可以分为:输入流和输出流 输入流和输出流 示意图: 字节流读取内容:二进制,音频,视频 优缺点:可以保证视频音频无损,效率低,没有缓冲区 字节流可 ...

  3. 踩坑,发现一个ShardingJdbc读写分离的BUG

    ShardingJdbc 怎么处理写完数据立即读的情况的呢? 写在前面 我本地使用了两个库来做写库(ds_0_master)和读库(ds_0_salve),两个库并没有配置主从. 下面我就使用库里的 ...

  4. Linux有趣命令

    通外网 下载使用阿里云镜像源:wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.re ...

  5. SQL语句中过滤条件放在on和where子句中的区别和联系

    摘要: 介绍在多表关联SQL语句中,过滤条件放在on和where子句中的区别--inner join中没区别,外连接就不一样. 综述   蚂蚁金服的一道SQL面试题如下:SQL语句中,过滤条件放在on ...

  6. 最强cron解析器

    背景 大家有没有这么一种困境 我现在需要去配置一个定时任务:"每天早上九点执行任务" 若你有一个好的定时任务平台,相信很容易就能配置完成.那若是没有定时任务平台呢?是不是就要自己写 ...

  7. MySQL 在 Kubernetes IPVS 模式下引发的 TCP 超时问题

    文章转载自:https://mp.weixin.qq.com/s/XQ2SlCYxvXPY0rRRO-CURA

  8. centos7安装sonarqube-9.2.4

    官方文档地址:https://docs.sonarqube.org/latest/requirements/requirements/ 使用 sonarqube 对 java 项目代码进行扫描的时候, ...

  9. es证书生成方式

    ./bin/elasticsearch-certutil ca --pem # 生成一个名字叫做elastic-stack-ca.zip的文件 unzip elastic-stack-ca.zip A ...

  10. 12. Fluentd部署:多Workers进程模式

    介绍如何使用Fluentd的多worker模式处理高访问量的日志事件.此模式会运行多个worker进程以最大利用多核CPU. 原理 默认情况下,一个Fluentd实例会运行一个监控进程和一个工作进程. ...