蓝桥杯每日一题20223.9.26

4407. 扫雷 - AcWing题库

题目描述

分析

此题目使用map等都会超时,所以我们可以巧妙的使用哈希模拟散列表,哈希表初始化为-1首先将地雷读入哈希表,找到地雷的坐标在哈希表中对应的下标,如果没有则此地雷的位置第一次出现,将其存入哈希表,di[key]表示哈希数组中key对应的地雷下标,在这些相同位置的地雷中取最大的半径,因为最大的半径炸的范围更多

枚举导弹,如果有地雷,且没有被访问过而且其在爆炸范围之内就可以将其进行bfs

最后遍历每个地雷看是否被标记,被标记就算答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int X = 1e9 + 1, M = 1e6 + 7, N = 5e4 + 10;
struct node
{
	int x, y, r;
}b[N];
ll h[M], id[M], res, n, m;
bool st[N];
ll get_he(int x, int y)//得到每个坐标的哈希值 
{
	return (ll)x * X + y;
}
int find(int x, int y)//找到坐标被哈希数组储存的下标 
{
	ll he = get_he(x, y);
	int key = (he % M + M) % M;//映射哈希数组内 
	while(h[key] != -1 && h[key] != he)
	{
		key ++;
		if(key == M)key = 0;
	}
	return key;
}
bool check(int x, int y,int r, int xx, int yy)//判断是否在爆炸范围内 
{
	int d = (x - xx) * (x - xx) + (y - yy) * (y - yy);
	return d <= r * r;
}
void bfs(int pos)
{
	queue<int>q;
	q.push(pos);
	st[pos] = true;
	while(!q.empty())
	{
		int t = q.front();
		q.pop();
		int x = b[t].x, y = b[t].y, r= b[t].r;
		for(int xx = x - r; xx <= x + r; xx ++)
		{
			for(int yy = y - r; yy <= y + r; yy ++)
			{
				int key = find(xx, yy);
				//是地雷,没有访问过,能炸到 
				if(id[key] && !st[id[key]] && check(x, y, r, xx, yy))
				{
					int pos = id[key];
					st[pos] = true;
					q.push(pos);
				}
			}
		}
	}
}
int main()
{
	cin >> n >> m;
	memset(h, -1, sizeof h);
	int x, y, r;
	for(int i = 1; i <= n; i ++)//地雷 
	{
		cin >> x >> y >> r;
		b[i] = {x, y, r};
		int key = find(x, y);//找到此地雷对应的下标 
		if(h[key] == -1)h[key] = get_he(x, y);//如果此下标没有出现过就加入 
		if(!id[key] || b[id[key]].r < r)
		{
			id[key] = i;
		}
	}
	for(int i = 1; i <= m; i ++)//排雷导弹
	{
		cin >> x >> y >> r;
		for(int xx = x - r; xx <= x + r; xx ++)//在r的范围内,但可以以圆外的方形区域作为边界 
		{
			for(int yy = y - r; yy <= y + r; yy ++)
			{
				int key = find(xx, yy);
				if(id[key] && !st[id[key]] && check(x, y, r, xx, yy))bfs(id[key]);
			}
		}	
	} 
	for(int i = 1; i <= n; i ++)
	{
		int key = find(b[i].x, b[i].y);
		int pos = id[key];
		if(pos && st[pos])res ++;
	}
	cout << res;
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值