UPC11456 视线(计算几何)
[提交] [状态] [命题人:admin]
题目描述
二维平面上,原点处有一个半径为R的圆。平面上有N个点,保证没有点在圆上或圆内,保证任意两个点不与圆相切,求互相可以看见的点的对数。
看见:对于两个点(x1,y1)和(x2,y2),他们的线段与圆没有交点。
计算对数时,(a,b)和(b,a)视为相同,且(a,a)不算点对。
输入
第一行,两个整数 N,R。
第 2 ~ N+1行,每行两个整数,表示点的坐标。
输出
一行,一个整数,表示能互相看见的点的对数。
样例输入
4 5
0 10
0 -10
10 0
-10 0
样例输出
4
提示
对于40%的数据,N≤1000。
对于100%的数据,N≤50000。
点的坐标为[−106,106]内的整数。
R的取值为[1,106]内的整数。
只能说昨天训练的时候复杂度分析对了…… 但是没想出来具体是要怎么sort
如上图所示,两个点互相可见有两种情况。
从A和B分别向圆做切线,会产生四个切点。
第一种情况中B的一个切点在A的两个切点之间,A的一个切点在B的两个切点
之间。第二种情况A的两个切点在B的两个切点之间。
所以把所有的切点求出来并排序,然后对于每一个点利用二分求出它两个切点之间有多少个切点(记为\(a_i\)), \(ans = \frac{\sum_{0}^{n-1} a_i}{2}\)
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1);
const double esp = 1e-9;
struct point {
double x, y;
} a[maxn];
struct node {
double begin, end;
} e[maxn];
vector s;
int dtoicmp(double a) {
if (fabs(a) < esp) return 0;
return a > 0 ? 1 : -1;
}
int main() {
// freopen("in.txt", "r", stdin);
int n;
double r;
cin >> n >> r;
for (int i = 0; i < n; i++) {
cin >> a[i].x >> a[i].y;
double len = sqrt(a[i].x * a[i].x + a[i].y * a[i].y);
double r1 = acos(r / len);
double r2 = atan2(a[i].y, a[i].x);
e[i] = {r2 - r1 + 2 * pi, r2 + r1 + 2 * pi};
if (dtoicmp(e[i].begin - 2 * pi) >= 0) e[i].begin -= 2 * pi;
if (dtoicmp(e[i].end - 2 * pi) >= 0) e[i].end -= 2 * pi;
if (dtoicmp(e[i].end - e[i].begin) <= 0) swap(e[i].end, e[i].begin);
s.push_back(e[i].begin);
s.push_back(e[i].end);
}
long long ans = 0;
sort(s.begin(), s.end());
long long from, to;
for (int i = 0; i < n; i++) {
from = lower_bound(s.begin(), s.end(), e[i].begin) - s.begin();
to = lower_bound(s.begin(), s.end(), e[i].end) - s.begin();
if (dtoicmp(e[i].end - e[i].begin - pi) >= 0)
ans = ans + 2 * n - (to - from - 1)-2;
else
ans = ans + to - from - 1;
}
cout << ans / 2 << endl;
return 0;
}
posted @
2019-05-22 19:24 Albert_liu 阅读(
...) 评论(
...) 编辑 收藏