称检测点查询
问题
给一个人的坐标,n个检测点的坐标,给出离这个人最近的三个检测点的编号,距离相等的选编号最小的。
思路
使用结构体记录,检测点的距离平方D,以及下标,使用结构体数组存储,然后在对数组进行排序,使用稳定排序法,这里使用冒泡排序。
#include <bits/stdc++.h>
using namespace std;
struct Point {
int index;
int D;
};
int main() {
int n, X, Y;
cin >> n >> X >> Y;
vector<Point> points(n);
int x, y, D;
Point temp;
for(int i = 0; i < n; i++) {
cin >> x >> y;
temp.D = pow(x - X, 2) + pow(y - Y, 2);
temp.index = i + 1;
points[i] = temp;
}
for(int i = 0; i < n - 1; i++) {
for(int j = 0; j < n - i -1; j++) {
if(points[j].D > points[j+1].D) {
swap(points[j], points[j+1]);
}
}
}
cout << points[0].index << endl << points[1].index << endl << points[2].index << endl;
return 0;
}
get
结构体的属性的访问也是点访问。
//万能头文件
#include <bits/stdc++.h>
pow 次方的头文件是 <cmath>
稳定的排序方法:
冒泡排序(Bubble Sort)
插入排序(Insertion Sort)
归并排序(Merge Sort)
忘记了,这里积累一下
//冒泡排序
void bubbleSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
std::swap(arr[j], arr[j+1]);
}
}
}
}
// 插入排序
void insertionSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i-1;
while (j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
}
//归并排序
void merge(std::vector<int>& arr, int l, int m, int r) {
int n1 = m-l+1;
int n2 = r-m;
std::vector<int> L(n1), R(n2);
for (int i = 0; i < n1; i++) {
L[i] = arr[l+i];
}
for (int j = 0; j < n2; j++) {
R[j] = arr[m+1+j];
}
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k++] = L[i++];
} else {
arr[k++] = R[j++];
}
}
while (i < n1) {
arr[k++] = L[i++];
}
while (j < n2) {
arr[k++] = R[j++];
}
}
void mergeSort(std::vector<int>& arr, int l, int r) {
if (l < r) {
int m = l + (r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
}
风险人群筛查
问题
给出若干个居民的经过的t对坐标点,已知风险区域,求出经过风险区域的居民个数,进一步的,如果有连续k个坐标都在风险区域内,则该居民在风险区域停留。
我的思路
遍历居民的t对坐标,遇到一个在区域内的,进入内层循环,判断是否有k-1个点也都在区域内,如果存在,则该居民在风险区域停留,stay和pass都计数,然后结束这个居民的循环。如果后续没有连续k-1个点都在区域内,则更新j的值为下一个没判断过点,继续进行判断。
在判断是否能连续的时候,此时应满足j/2 <= t - k ,后续可能存在k-1个点连续,再进一步判断,否则就直接break,不可能有停留的情况。
(修改错误很久很久,最后宁宁发现是这个我写成了j/2 <= t - k-1,应该是在进行判断的时候,至少是倒数第k个,后续才有k-1个)
最终再结束这个居民的时候,如果(flag1 && !flag2)有经过,没停留,则,pass++,然后继续下一位居民
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, k, t, xl, yd, xr, yu;
cin >> n >> k >> t >> xl >> yd >> xr >> yu;
int pass = 0, stay = 0;
int x , y;
vector<vector<int> > records(n, vector<int>(2*t));
for(int i = 0; i < n; i++) {
for(int j = 0; j < 2 * t; j++) {
cin >> records[i][j];
}
}
// 遍历i位居民
for(int i = 0; i < n; i++) {
int flag1 = 0, flag2 = 0;
// 遍历t对坐标
for(int j = 0; j < 2 * t; j += 2) {
x = records[i][j];
y = records[i][j+1];
if(x >= xl && x <= xr && y >= yd && y <= yu) {
flag1 = 1; //经过
// 进一步判断是否连续k个,即停留
if(j/2 <= t - k) {//要往后再k-1个,但是,此时的j要满足后面有k对!!!!
//往后判断k-1个点
int s;
for(s = 1; s < k; s++) {
x = records[i][j + 2 * s];//这里的下标注意!!
y = records[i][j + 1 + 2 * s];
if(x >= xl && x <= xr && y >= yd && y <= yu) {
continue;
} else {
j += 2 * s;//更新j值,直接跳到下一个没判断过的点
break;//结束本层for循环
}
}
//如果没有break的话,s等于k,则说明有连续k个,判断为stay,结束这个居民
if(s == k) {
stay++;
pass++;
flag2 = 1;
break;//这位居民不用看了
}
}
}
}// 对t对坐标判断结束,没有通过stay的方式提前结束,则判断是否有pass
if(flag1 && !flag2) {
pass++;
}
}
cout << pass << endl << stay << endl;
return 0;
}
优秀思路
自己的方法太麻烦了,还很容易错,看到一个好简单的思路
CCF- CSP 202009-2风险人群筛查 满分题解
很聪明简洁的思路,问题的关键就在于要判断是否有连续的k个,那就遍历所有点,记录每组最大的连续值,最后判断这个值是否大于等于k,是的话就是stay,不是的话,如果大于0,就是pass。
get
orz,真的好厉害,这个思路我怎么就想不到。我的思路好僵硬,生硬的,一层层的嵌套,复杂。
对啊,人家就是要判断有没有存在大于等于k的连续存在,直接算出来最大连续不就好了。