csp 20-09-01称检测点查询 & 02风险人群筛查

称检测点查询

问题

给一个人的坐标,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的连续存在,直接算出来最大连续不就好了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值