扫雷


题目描述:

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

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

在一个二维平面上放置着 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. tty的crash分析

    crash> btPID: 410629 TASK: ffff883fea379fa0 CPU: 10 COMMAND: "jupyter-lab"#0 [ffff8823c ...

  2. JWT漏洞学习

    JWT漏洞学习 什么是JWT? JWT是JSON Web Token的缩写,它是一串带有声明信息的字符串,由服务端使用加密算法对信息签名,以保证其完整性和不可伪造性.Token里可以包含所有必要的信息 ...

  3. Java连接简单使用ElasticSearch

    目录 1. 添加依赖 2. 代码,无账号密码 3. 代码,有账号密码,并且是https方式 4. 参考文章 1. 添加依赖 <!-- https://mvnrepository.com/arti ...

  4. 高颜值,类似Fliqlo的翻页时钟-BdTab新标签页插件组件

    起因: 很多用户在使用BdTab插件时,反馈说希望添加一个时钟的功能, 而BdTab又是组件模块化的插件,于是在空余时间就用html+js+css写了一款高颜值的分页时钟 源码如下: 需要其他网页组件 ...

  5. 第八十三篇:Vue购物车(四) 总价计算

    好家伙, 1.总价计算 来了,又先是一波分析: 我们用一个计算属性amt 我们把item中被勾选的项用一个过滤器过滤器来 然后用一个循环相加,把商品的价格乘以商品的数量, 把这个总值返回出去, 然后组 ...

  6. 第四十四篇:Git分支(关键知识点)

    好家伙, GIT分支 分支就像是平行宇宙,两个平行宇宙自己平行,不相干扰,平安无事, 某一天它想不开,合并了.然后就变成了我写这篇博客的动机了. 1.关于Git分支中常用的指令 列出所有分支 git ...

  7. SpringBoot使用libreoffice转换PDF

    1.简介 有时候我们需要在程序中使用到office的转换和预览功能,本文就针对这个需求记录了较为简单的office转换和功能:jodconverter.当然也有aspose和其他开源第三方(kkfil ...

  8. Ubuntu20.04和Docker环境下安装Redash中文版

    创建Ubunt20.04虚拟机,请参考:https://www.linuxidc.com/Linux/2020-03/162547.htm 一.安装基础环境: # 1.更换APT国内源 sudo se ...

  9. 跟我学Python图像处理丨带你掌握傅里叶变换原理及实现

    摘要:傅里叶变换主要是将时间域上的信号转变为频率域上的信号,用来进行图像除噪.图像增强等处理. 本文分享自华为云社区<[Python图像处理] 二十二.Python图像傅里叶变换原理及实现> ...

  10. PAT (Basic Level) Practice (中文)1015 德才论 分数 25

    宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取人之术,苟不得圣人,君子 ...