zoukankan      html  css  js  c++  java
  • UPC11456 视线(计算几何)

    视线

    时间限制: 1 Sec 内存限制: 128 MB
    提交: 21 解决: 2

    [提交] [状态] [命题人: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<double> 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;
    }
    
  • 相关阅读:
    WebEssentials 在vs2013 update5安装报错的解决方法.
    提高代码质量系列之三:我是怎么设计函数的?
    ValueInjecter----最好用的OOM(以微信消息转对象举例)
    我的第一个python程序--给2.x的print代码加上括号
    提高代码质量系列之二:重构小技巧——if篇
    提高代码质量系列之一:尽可能少写注释.
    Two-machine debugging
    12306个人敏感信息泄露
    纯手工秒杀VM,SE等虚拟机Handle
    2014版QQ个性显IP(源码+Bin)
  • 原文地址:https://www.cnblogs.com/albert-biu/p/10907996.html
Copyright © 2011-2022 走看看