第十三届蓝桥杯B组题:扫雷

扫雷

题目描述:

在这里插入图片描述
然后我代码上标注并解释的的很详细,就直接上代码了~~~

#include <bits/stdc++.h>
using namespace std;
//第十三届蓝桥杯扫雷
const int N = 50010, M = 999997;//N:最多的点数 M用于哈希  在允许的范围内M大一点比较好
struct circle {
	int x, y, r;
}cir[N];
int id[M];//记录相同位置半径最大的雷在cir中的坐标
bool sc[M];//判断某位置的雷是否被引爆
#define ll long long
ll h[M];//储存哈希值
		//注:xxxxll(后面两个是LL 不是11 代表将xxxx转化为long long 类型)
ll get_key(int x, int y) {
	return x * 1000000001ll + y;//这样可以尽量使每个坐标拥有一个特定的哈希值
}
int find(int x, int y) {
	ll key = get_key(x, y);
	int t = (key%M + M) % M;//这样可以确保t为正值 并且控制哈希值的范围
	while (h[t] != -1 && h[t] != key) {//如果位置已经被占用则向后寻找
		if (++t == M)t = 0;//防止数组越界
	}
	return t;//相当于根据哈希值在h数组中找好了
}
int sqr(int x) {
	return x*x;
}
void dfs(int x, int y, int r) {
	sc[find(x, y)] = true;//先标记被引爆
	for (int i = x - r; i <= x + r; i++) {//枚举被引爆雷的周围
		for (int j = y - r; j <= y + r; j++) {
			if (sqr(i-x) + sqr(j-y) <= sqr(r)) {
				int t = find(i, j);
				if (id[t] && !sc[t]) {
					dfs(i, j, cir[id[t]].r);
				}
			}
		}
	}
}

int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	memset(h, -1, sizeof(h));//代表h[i]==-1代表h[i]位置没雷
	for (int i = 1; i <= n; i++) {
		int x, y, r;
		scanf("%d%d%d", &x, &y, &r);
		cir[i] = { x,y,r };
		int t = find(x, y);//寻找x y 的位置
		if (h[t] == -1)h[t] = get_key(x, y);//get_key:返回x y的哈希值
		if (!id[t] || cir[id[t]].r < r)id[t] = i;//更新id数组  这里id的值改变只改变了它的影响范围


	}
	while (m--) {
		int x, y, r;
		scanf("%d%d%d", &x, &y, &r);
		for (int i = x - r; i <= x + r; i++) {
			for (int j = y - r; j <= y + r; j++) {
				if (sqr(i-x) + sqr(j-y) <= sqr(r)) {//x^2+y^2<=r^2 枚举圆内所有点
					int t = find(i, j);//找到点在哈希表中的位置
					if (id[t] && !sc[t]) {//如果有雷且没有被引爆
						dfs(i, j, cir[id[t]].r);//深搜 主要为了找到全部被引爆的雷 sc[i]==true代表i位置被引爆
					}

				}
			}
		}
	}
	//遍历
	int res = 0;
	for (int i = 1; i <= n; i++) {
		if (sc[find(cir[i].x, cir[i].y)])res++;//枚举所有雷判断他所在的坐标是否引爆 这样即使多个雷在同一个坐标也能被计算
	}
	printf("%d\n", res);
	return 0;
}

好了,一篇随机笔记就写完了!

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值