用坐标集合判断四个正交邻居和四个对角邻居,按对角垃圾数计分。
OJ: shumeng
题目 ID: CSP201912B
难度:入门
标签:模拟集合坐标
日期: 2026-07-31 16:21
形式化题目
平面上有
思路
朴素做法
对每个垃圾点都扫描全部坐标,线性检查它需要的八个邻居。时间复杂度
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-31 16:21
* update_at: 2026-08-17 22:41
*/
// brute.cpp:小数据暴力解,对每个候选点扫描所有垃圾坐标,检查八个相邻位置。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int n;
long long point_x[MAXN], point_y[MAXN];
// 线性扫描全部垃圾坐标,判断 (x, y) 处是否有垃圾。
bool has_point(long long x, long long y) {
for (int i = 1; i <= n; i++) {
if (point_x[i] == x && point_y[i] == y) return true;
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> point_x[i] >> point_y[i];
}
int answer[5] = {};
for (int i = 1; i <= n; i++) {
long long x = point_x[i], y = point_y[i];
// 先确认四个正交邻居,再统计四个对角邻居作为得分。
if (!has_point(x - 1, y) || !has_point(x + 1, y)
|| !has_point(x, y - 1) || !has_point(x, y + 1)) {
continue;
}
int score = 0;
score += has_point(x - 1, y - 1);
score += has_point(x - 1, y + 1);
score += has_point(x + 1, y - 1);
score += has_point(x + 1, y + 1);
answer[score]++;
}
for (int i = 0; i <= 4; i++) cout << answer[i] << '\n';
return 0;
}坐标集合查询
把所有坐标放入集合。每个候选点只做 8 次集合查询:先确认四个正交邻居,成立后统计四个对角邻居,得到分数并计数。坐标范围很大且可以为负,所以使用 long long 保存坐标。
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-31 16:21
* update_at: 2026-08-17 22:41
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int n;
long long point_x[MAXN], point_y[MAXN]; // 各垃圾点坐标
set<pair<long long, long long> > points; // 坐标集合,用于 O(log n) 查询某个位置是否有垃圾
// 判断坐标 (x, y) 处是否存在垃圾。
bool has_point(long long x, long long y) {
return points.find(make_pair(x, y)) != points.end();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> point_x[i] >> point_y[i];
points.insert(make_pair(point_x[i], point_y[i]));
}
int answer[5] = {}; // 得分为 0..4 的回收站选址个数
for (int i = 1; i <= n; i++) {
long long x = point_x[i], y = point_y[i];
// 上下左右四个正交邻居必须全部存在垃圾。
if (!has_point(x - 1, y) || !has_point(x + 1, y)
|| !has_point(x, y - 1) || !has_point(x, y + 1)) {
continue;
}
// 评分:四个对角位置中有几处存在垃圾。
int score = 0;
score += has_point(x - 1, y - 1);
score += has_point(x - 1, y + 1);
score += has_point(x + 1, y - 1);
score += has_point(x + 1, y + 1);
answer[score]++;
}
for (int i = 0; i <= 4; i++) cout << answer[i] << '\n';
return 0;
}复杂度
- 时间:集合构建和每次查询为
,总时间复杂度 。 - 空间:
。
总结
小范围几何邻居判断不需要建网格。将实际出现的坐标存为集合后,平移八个固定方向逐一查询即可。
