SGU 253. Theodore Roosevelt

题目:http://acm.sgu.ru/problem.php?contest=0&problem=253

本题要求在一个给定凸包,一些点有几个是在凸包内的(包括边界)。

以前判断某一点是否在多边形内,可以叉积依次求面积的方法,但是每次查询耗时O(n)。

所以这里提一种每次查询只需要O(lgn)的解法。

就是先按极角排序,然后二分求给定点的极角范围,叉积计算进行求解。

一开始我的线段拐向求反了,导致wa on test 5。一定要小心啊。

而且swap写的一开始也有问题,谢学弟帮我排bug。二分法的临界仍然需要熟练掌握。是在担心写错,就直接用STL upper_bound吧。不要自己写了。

http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;

const double eps = 1e-8;
struct Point
{
    long long  x;
    long long y;
    double angle;
    long long dis;
    Point() {}
    Point(long long _x,long long _y):x(_x),y(_y) {}
    friend Point operator + (Point a,Point b)
    {
        return Point(a.x+b.x , a.y+b.y);
    }
    friend Point operator - (Point a,Point b)
    {
        return Point(a.x-b.x , a.y-b.y);
    }
};

int dcmp(double x)
{
    if(fabs(x)<eps)
    {
        return 0;
    }
    return x>0?1:-1;
}

double det(Point a,Point b)
{
    return a.x*b.y-a.y*b.x;
}
double det(Point a,Point b,Point o)
{
    return det(a-o,b-o);
}
double det(Point a,Point b,Point c,Point d)
{
    return det(b-a,d-c);
}

Point p[100005];

bool cmp(Point a,Point b)
{
    return dcmp(a.angle-b.angle)<0 || (dcmp(a.angle - b.angle)==0 && a.dis <b.dis);
}
void swap(Point &a,Point &b)
{
    Point c = b;
    b = a;
    a = c;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    int n,m,k;
    while(scanf(" %d %d %d",&n,&m,&k)!=EOF)
    {
        Point le;
        int le_num = 0;
        for(int i=0;i<n;i++)
        {
            scanf(" %lld %lld",&p[i].x,&p[i].y);
            //求最下左点
            if(i==0)
            {
                le.x = p[0].x;
                le.y = p[0].y;
                le_num = 0;
            }
            else
            {
                if(p[i].y<le.y || (p[i].y == le.y && p[i].x < le.x))
                {
                    le = p[i];
                    le_num = i;
                }
            }
        }
        swap(p[0],p[le_num]);

        for(int i=1;i<n;i++)
        {
            p[i].angle = atan2(p[i].y - p[0].y,p[i].x - p[0].x);
            p[i].dis = (p[i].x - p[0].x)*(p[i].x - p[0].x) + (p[i].y - p[0].y)*(p[i].y - p[0].y);
        }
        sort(p+1,p+n,cmp);
        int x,y;
        int num = 0;
        for(int i=0;i<m;i++)
        {
            Point temp;
            scanf(" %lld %lld",&temp.x,&temp.y);
            if(temp.x == p[0].x && temp.y == p[0].y)
            {
                num++;
            }
            else
            {
                temp.angle = atan2(temp.y-p[0].y,temp.x-p[0].x);
                int low = 1;
                int high = n-1;
                if(dcmp(temp.angle - p[high].angle)>0 || dcmp(temp.angle - p[low].angle)<0)
                {
                    continue;
                }
                int pos = 1;
                //求upper_bound
                while(low<high)
                {
                    int mid = (low + high)/2;
                    if( p[mid].angle <= temp.angle)
                    {
                        low = mid + 1;
                        pos = low;
                    }
                    else
                    {
                       high = mid;
                       pos = high;
                    }
                }
                if(pos == n)
                {
                    pos--;
                }
                if(det(temp,p[pos -1],p[pos])>=0)
                {
                    num++;
                }
            }
        }
        if(num>=k)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}


参考: http://hi.baidu.com/aekdycoin/item/2d54f9c0fef55457ad00efd6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值