一、题目大意¶
给定\(n\)条端点在坐标轴正半轴上,且坐标值递增的线段,给定坐标平面上一个固定点\(P\),查询有多少条线段在\(P\)的左边。
二、算法分析及代码实现¶
由于输入的线段端点坐标是无序的,因此需要先对坐标进行排序,为此使用快速排序算法,时间复杂度\(O(n\log{n})\)。
void quicksort(long long num[], int left, int right) {
if(left < right) {
int i = left, j = right, temp = num[left];
while(i < j) {
while(i < j && num[j] >= temp) {
j --;
}
if(i < j) {
num[i ++] = num[j];
}
while(i < j && num[i] < temp) {
i ++;
}
if(i < j) {
num[j --] = num[i];
}
}
num[i] = temp;
quicksort(num, left, i -1);
quicksort(num, i + 1, right);
}
else {
return;
}
}
接着,我们要判断点与线段的位置关系,自然想到用向量叉积的大小来判断。设线段为\(PQ\),点为\(R\),按逆时针方向构造向量\(\overrightarrow{PQ}, \overrightarrow{QR}\),计算\(\overrightarrow{PQ} \times \overrightarrow{QR}\)的值,若值大于等于0,则点在线段上或在线段右侧,则点与原点O的连线与该线段有交点;反之就没有交点。由此可以定义函数\(check\)来判断是否有交点。
int check(PointInfo point, long long num_x, long long num_y) {
long long area = num_x * point.y + num_y * point.x - num_x * num_y;
if(area >= 0) {
return 1;
}
else {
return 0;
}
}
为了提高效率,由于线段的排列是有序的,则在计算交点个数的时候可以采用二分查找,快速找到最后一个有交点的线段的序号,则也就知道了交点的个数,时间复杂度\(O(\log{n})\)。
for(int i = 0; i < m; i ++) {
int low = 0;
int high = n;
int mid = (low + high) / 2;
while(low < high - 1) {
if (check(point[i], num_x[mid], num_y[mid]) == 1){
low = mid;
}
else {
high = mid;
}
mid = (low + high) / 2;
}
if(low == 0 && check(point[i], num_x[0], num_y[0]) == 0) {
printf("%d\n", low);
}//此处当low=0时进行特判
else {
printf("%d\n", low + 1);
}
}
三、复杂度分析¶
本题算法的时间复杂度为\(O(n\log{n})\),空间复杂度为\(O(n)\)。
评论