题目大意:给定一个盒子的左上角和右下角坐标,然后给n条线,可以将盒子分成n+1个部分,再给m个点,问每个区域内有多少各点
这个题用到关键的一步就是向量的叉积,假设一个点m在 由abcd围成的四边形区域内,那么向量ab, bc, cd, da和点的关系就是,点都在他们的同一侧,我是按照逆时针来算的,所以只需要判断叉积是否小于0就行了。还有一个问题就是这个题要求时间是2s,所以直接找,不用二分也能过,不过超过1s了,最好还是二分来做,二分时间170ms,二分的时候要把最左边的一条边和最右边的一条边都要加到数组中去
代码一(直接找区域)
#include<iostream> #include <cstdio> #include <string.h> using namespace std; const int N = 15500; struct point{ int x, y; }; int n, m, ans[5500]; point upper_left, lower_left, upper_right, lower_right, p[N]; double direction(point a, point b, point c)//判断方向 { point t1, t2; t1.x = c.x - a.x; t1.y = c.y - a.y; t2.x = b.x - a.x; t2.y = b.y - a.y; return (t1.x * t2.y * 1.0 - t1.y * t2.x * 1.0); } int main() { while (~scanf("%d", &n) && n) { memset(ans, 0, sizeof(ans)); int a, b; scanf("%d %d %d %d %d", &m, &upper_left.x, &upper_left.y, &lower_right.x, &lower_right.y); lower_left.x = upper_left.x; lower_left.y = lower_right.y; upper_right.x = lower_right.x; upper_right.y = upper_left.y; for (int i = 0; i < 2 * n; i++) { scanf("%d %d", &a, &b); p[i].x = a; p[i].y = upper_left.y; p[++i].x = b; p[i].y = lower_right.y; } point tmp; double d1, d2, d3, d4; for (int i = 0; i < m; i++) { scanf("%d %d", &tmp.x, &tmp.y); //判断是否在第一个区域内 d1 = direction(upper_left, lower_left, tmp); d2 = direction(lower_left, p[1], tmp); d3 = direction(p[1], p[0], tmp); d4 = direction(p[0], upper_left, tmp); if (d1 <= 0 && d2 <= 0 && d3 <= 0 && d4 <= 0) { ans[0]++; continue; } bool flag = false; for (int j = 0; j < 2 * n - 2; j += 2) { d1 = direction(p[j], p[j + 1], tmp); d2 = direction(p[j + 1], p[j + 3], tmp); d3 = direction(p[j + 3], p[j + 2], tmp); d4 = direction(p[j + 2], p[j], tmp); if (d1 <= 0 && d2 <= 0 && d3 <= 0 && d4 <= 0) { ans[j / 2 + 1]++; flag = true; break; } } if (flag) continue; //d1 = direction(p[2 * n - 2], p[2 * n - 1], tmp); //d2 = direction(p[2 * n - 1], lower_right, tmp); //d3 = direction(lower_right, upper_right, tmp); //d4 = direction(upper_right, p[n * 2 - 2], tmp); //if (d1 <= 0 && d2 <= 0 && d3 <= 0 && d4 <= 0) ans[n]++; } for (int i = 0; i <= n; i++) printf("%d: %d\n", i, ans[i]); puts(""); } return 0; }
代码二(二分法)
#include<iostream> #include <cstdio> #include <string.h> using namespace std; const int N = 15500; struct point{ int x, y; }; int n, m, ans[5500]; point upper_left, lower_left, upper_right, lower_right, p[N];//各个角 double direction(point a, point b, point c)//判断方向,判断点c在向量ab的哪一侧,如果返回是负值则在逆时针那侧 { point t1, t2; t1.x = c.x - a.x; t1.y = c.y - a.y; t2.x = b.x - a.x; t2.y = b.y - a.y; return (t1.x * t2.y * 1.0 - t1.y * t2.x * 1.0); } void dichotomization(point tmp)//二分法判断在那块区间内 { int left, right, mid; left = 0; right = n + 1; mid = (left + right) >> 1; while (left < right) { if (left + 1 == right) { ans[left]++; break; } double d = direction(p[mid * 2], p[mid * 2 + 1], tmp); if (d < 0) left = mid; else right = mid; mid = (left + right) >> 1; } } int main() { while (~scanf("%d", &n) && n) { memset(ans, 0, sizeof(ans)); int a, b; scanf("%d %d %d %d %d", &m, &upper_left.x, &upper_left.y, &lower_right.x, &lower_right.y); lower_left.x = upper_left.x; lower_left.y = lower_right.y; upper_right.x = lower_right.x; upper_right.y = upper_left.y; p[0] = upper_left;//将边角点加入p数组,为了二分 好计算 p[1] = lower_left; for (int i = 2; i < 2 * n + 2; i++) { scanf("%d %d", &a, &b); p[i].x = a; p[i].y = upper_left.y; p[++i].x = b; p[i].y = lower_right.y; } p[2 * n + 2] = upper_right; p[2 * n + 3] = lower_right; point tmp; for (int i = 0; i < m; i++) { scanf("%d %d", &tmp.x, &tmp.y); dichotomization(tmp); } for (int i = 0; i <= n; i++) printf("%d: %d\n", i, ans[i]); puts(""); } return 0; }
时间: 2024-11-08 21:56:12