关键点:时间复杂度
1. 暴力枚举方法:
在暴力枚举方法中,会针对每个点,检查它周围的所有可能的点来判断它是否构成一个正方形的一部分,以及它的对角线上的点是否存在。
- 时间复杂度:对于每个点,你需要检查固定数量的邻居(通常是8个方向),因此单点的检查是O(1)。但是,对于n个点,总的时间复杂度是O(n)。然而,如果我们要检查每个点是否与其他点形成特定的正方形结构,特别是在计算得分时,如果用暴力枚举去查找每个点的四个对角是否存在,对于每个点可能需要与其它所有点进行比较,这将使时间复杂度上升至O(n²)。
2. 使用映射和向量的方法
-
映射的使用:通过使用映射(
mapX和mapY),代码可以在O(1)的时间内直接访问任何特定坐标的点(假设哈希操作的时间复杂度是O(1))。这大大减少了需要检查的点的数量。 -
点的插入和检索:将每个点插入映射中的时间复杂度是O(1),总共是O(n)。检索一个点是否存在于给定的x或y坐标的时间复杂度也是O(1),但是因为需要检查的是固定的几个点(而不是所有的点),所以整体效率更高。
-
时间复杂度:总的来说,主要的过程,包括构建映射和检查点,时间复杂度是O(n)。即使在检测和计算分数过程中需要进行多次映射查找,这些操作的时间复杂度仍然是O(1),因此不会显著增加总体时间复杂度。
结论:
相比于暴力枚举方法,上述代码通过使用映射和向量来优化数据的组织和访问,从而显著降低了时间复杂度。在暴力方法中,尤其是在最坏情况下,时间复杂度可以达到O(n²),而使用映射和向量的方法将这一复杂度降低到O(n),这在处理大量数据时可以极大地提高效率。
解题思路
1. 检测功能 detect:
此功能的目的是确定给定的点是否能够作为回收站,这是通过检查以下条件来实现的:
-
横向检测:
- 检查给定点的左边(
x - 1)和右边(x + 1)是否都存在点。这是通过在同一纵坐标y(使用mapY映射)下搜索对应的x值完成的。 - 如果两边都有点,
flagX将被设置为2。
- 检查给定点的左边(
-
纵向检测:
- 检查给定点的上面(
y + 1)和下面(y - 1)是否都存在点。这是通过在同一横坐标x(使用mapX映射)下搜索对应的y值来完成的。 - 如果上下都有点,
flagY将被设置为2。
- 检查给定点的上面(
-
确定回收站:只有当
flagX和flagY都为2,即点周围正好有四个点(左、右、上、下),该点才被视为正方形的一部分。
2. 获取分数 getScore:
- 对于给定点的每个对角方向(左上、右上、左下、右下),函数会检查相应的坐标上是否有点存在。
- 这是通过查询
mapX映射来实现的,对每个检查的x坐标,函数会在该坐标下搜索对应的y值。 - 每发现一个对角方向被占据,得分增加1。
- 最终得分范围从0(没有对角被占据)到4(所有对角都被占据)。
3. 统计得分:
在主函数中,代码执行以下操作:
-
遍历所有点:对于列表中的每个点,首先使用
detect函数检查该点是否构成正方形的一部分。如果是,那么使用getScore函数来确定该点的得分。 -
更新得分列表:根据
getScore函数返回的得分,增加scoreList相应索引下的值。例如,如果一个点的得分是3,那么scoreList[3]的值就会增加1。 -
输出结果:遍历
scoreList,按分数0至4的顺序打印出每个分数的点的数量。
完整代码
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int n;
vector<int>scoreList(5);
map<long long, vector<long long>>mapX, mapY;
struct MyPoint
{
long long x, y;
};
bool dectect(int x, int y)
{
// 横向检测
int myX = x - 1, xRight = x + 1, flagX = 0;
for (auto& it : mapY[y]) {
if (it == myX || it == xRight) flagX++;
}
// 纵向检测
int yLeft = y - 1, yRight = y + 1, flagY = 0;
for (auto& it : mapX[x]) {
if (it == yLeft || it == yRight) flagY++;
}
return flagX == 2 && flagY == 2;
}
int getSroce(int x, int y)
{
int score = 0;
// 左上
int myX = x - 1, myY = y + 1;
for (auto& it : mapX[myX]) {
if (it == myY) score++;
}
// 右上
myX = x + 1, myY = y + 1;
for (auto& it : mapX[myX]) {
if (it == myY) score++;
}
// 左下
myX = x - 1, myY = y - 1;
for (auto& it : mapX[myX]) {
if (it == myY) score++;
}
// 右下
myX = x + 1, myY = y - 1;
for (auto& it : mapX[myX]) {
if (it == myY) score++;
}
return score;
}
int main() {
cin >> n;
vector<MyPoint>pointList(n);
for (size_t i = 0; i < n; i++)
{
cin >> pointList[i].x >> pointList[i].y;
mapX[pointList[i].x].push_back(pointList[i].y);
mapY[pointList[i].y].push_back(pointList[i].x);
}
for (auto& it : pointList)
{
if (dectect(it.x, it.y)) scoreList[getSroce(it.x, it.y)]++;
}
for (auto& it : scoreList)
{
cout << it << endl;
}
return 0;
}
文章讨论了在CSP问题中,通过使用映射和向量数据结构,优化回收站选址算法的时间复杂度,从暴力枚举的O(n²)降低到O(n),提高了处理大规模数据的效率。
&spm=1001.2101.3001.5002&articleId=137059094&d=1&t=3&u=f8dcd3f3d9c2444098216dabd8a76a7c)

被折叠的 条评论
为什么被折叠?



