扫雷
题目描述:
然后我代码上标注并解释的的很详细,就直接上代码了~~~
#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;
}
好了,一篇随机笔记就写完了!