• Gym 101128J Saint John Festival(凸包 + 二分判点和凸包关系)题解


    题意:给你一堆黑点一堆红点,问你有最多几个黑点能找到三个红点,使这个黑点在三角形内?

    思路:显然红点组成的凸包内的所有黑点都能做到。但是判断黑点和凸包的关系朴素方法使O(n^2),显然超时。那么我现在有一个更好的方法判断点和凸包的关系。我固定一个红点,然后找连续两个红点使黑点 i 在这个三角形内(向量判),然后用二分查找是否存在这样的两个连续红点。这样复杂度为nlogn。

    注意凸包不要用atan2的那种,会有精度误差...

    代码:

    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include <iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 1e4 + 10;
    const int M = maxn * 30;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1000000007;
    struct point
    {
        double x,y;
    }p[100000],a[100000],b[100000], g;
    int n, tot;
    bool cmp(point A,point B)
    {
        if(A.x!=B.x)
        return A.x<B.x;
        return A.y<B.y;
    }
    point operator -(point A,point B)
    {
        point c;
        c.x=A.x-B.x;
        c.y=A.y-B.y;
        return c;
    }
    double cross(point A,point B)
    {
        return A.x*B.y-B.x*A.y;
    }
    void dopack()
    {
        tot=0;
        for(int i=1;i<=n;i++)
        {
            while(tot>1&&cross(p[tot-1]-p[tot-2],a[i]-p[tot-2])<=0)tot--;
            p[tot++]=a[i];
        }
        int k=tot;
        for(int i=n-1;i>0;i--)
        {
            while(tot>k&&cross(p[tot-1]-p[tot-2],a[i]-p[tot-2])<=0)tot--;
            p[tot++]=a[i];
        }
        if(n>1)tot--;
    }
    double turn(point st, point en, point q){
        //正数:点在向量左侧
        //负数:点在向量右侧
        //0:点在向量直线上
        return (st.x - q.x) * (en.y - q.y) - (en.x - q.x) * (st.y - q.y);
    }
    int mid(){
        int l, r;
        l = 1, r = tot - 2;
        while(l <= r){
            int m = (l + r) >> 1;
            if(turn(p[0], p[m], g) >= 0 && turn(p[0], p[m + 1], g) <= 0){
                if(turn(p[m], p[m + 1], g) >= 0) return 1;
                return 0;
            }
            if(turn(p[0], p[m], g) >= 0){
                l = m + 1;
            }
            else{
                r = m - 1;
            }
        }
        return 0;
    }
    int main(){
        int m;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lf%lf", &a[i].x, &a[i].y);
        sort(a+1,a+1+n,cmp);
        dopack();
    //    for(int i = 0; i < tot; i++){
    //        printf("* %lf %lf
    ", p[i].x, p[i].y);
    //    }
        scanf("%d", &m);
        int ans = 0;
        for(int i = 1; i <= m; i++){
            scanf("%lf%lf", &g.x, &g.y);
            ans += mid();
        }
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    SVN安装
    MS SQL Server 查询元数据
    MS SQL Server 时间函数
    Codeforces 666E Forensic Examination (后缀自动机 + 线段树合并)
    2020牛客暑期多校训练营(第八场) H Hard String Problem
    2020牛客暑期多校训练营(第四场) B Count New String
    2020牛客暑期多校训练营(第四场) A Ancient Distance
    2020杭电多校第三场 1007 Tokitsukaze and Rescue
    codeforces 1037H
    2020牛客暑期多校训练营(第三场) H Sort the Strings Revision
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10821551.html
Copyright © 2020-2023  润新知