SGU 253 Theodore Roosevelt 快速判断点是否在凸包内

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

题意简单易懂...给你n个点的凸包(经测试已经是极角序)...判断m个点是否在凸包内...数量>=k就输出YES

46ms过的...貌似数据很水...但暴力判断每个点复杂度O(n*m)肯定T了...

二分可以优化到O(mlogn)   -----该算法受到AC巨巨的启发:http://hi.baidu.com/aekdycoin/item/2d54f9c0fef55457ad00efd6

把凸包分成n-2个三角形...然后二分点是否在这些三角形内即可...注意一下只有三个点的情况即可

/********************* Template ************************/
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;

#define EPS         1e-8
#define MAXN        100005
#define MOD         (int)1e9+7
#define PI          acos(-1.0)
#define INF         ((1LL)<<50)
#define max(a,b)    ((a) > (b) ? (a) : (b))
#define min(a,b)    ((a) < (b) ? (a) : (b))
#define max3(a,b,c) (max(max(a,b),c))
#define min3(a,b,c) (min(min(a,b),c))
#define BUG         cout<<"BUG! "<<endl
#define LINE        cout<<"------------------"<<endl
#define L(t)        (t << 1)
#define R(t)        (t << 1 | 1)
#define Mid(a,b)    ((a + b) >> 1)
#define lowbit(a)   (a & -a)
#define FIN         freopen("in.txt","r",stdin)
#pragma comment     (linker,"/STACK:102400000,102400000")

// typedef long long LL;
// typedef unsigned long long ULL;
// typedef __int64 LL;
// typedef unisigned __int64 ULL;
// int gcd(int a,int b){ return b?gcd(b,a%b):a; }
// int lcm(int a,int b){ return a*b/gcd(a,b); }

/*********************   F   ************************/
struct POINT{
    double x,y;
    POINT(double _x = 0, double _y = 0):x(_x),y(_y){};
    void show(){
        cout<<x<<" "<<y<<endl;
    }
};
POINT p[MAXN],wp[MAXN];
double multiply(POINT sp,POINT ep,POINT op){ //叉积
    return (sp.x-op.x) * (ep.y-op.y) - (ep.x-op.x) * (sp.y-op.y);
}
bool onseg(POINT a,POINT s,POINT e){   // 判断点是否在线段上
    if(multiply(a,s,e) == 0 && a.x <= max(s.x,e.x) && a.x >= min(s.x,e.x)
       && a.y <= max(s.y,e.y) && a.y >= min(s.y,e.y))
        return true;
    return false;
}
bool inside(POINT pp,POINT sp,POINT ep,POINT op){ //判断点pp是否在三角形中(极角序)
    if(onseg(pp,sp,ep) || onseg(pp,sp,op) || onseg(pp,ep,op)) //如果在三角形上
        return true;
    if(multiply(sp,ep,pp) > 0 && multiply(ep,op,pp) > 0
       && multiply(sp,op,pp) < 0)  //如果在三角形内
           return true;
    return false;
}
bool bsearch(POINT a,int len){    //二分所构造的三角形
    int l = 1,r = len,m;
    while(l < r){
        m = (l + r) / 2;
        if(inside(a,p[0],p[m],p[m+1]) == true) return true;
        if(multiply(p[0],p[m],a) >= 0 && multiply(p[0],p[m+1],a) <= 0
            && multiply(p[m],p[m+1],a) < 0) return false;
        if(multiply(p[0],p[m],a) > 0 && multiply(p[0],p[m+1],a) > 0)
            l = m + 1;
        else r = m;
    }
    return false;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,m,k,tmp = 0,cnt = 0;
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 0 ; i < n ; i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    p[n] = p[0];
    for(int i = 0 ; i < m ; i++){
        scanf("%lf%lf",&wp[i].x,&wp[i].y);
        if(bsearch(wp[i],n-1) == true) cnt++;
    }
    if(cnt >= k) printf("YES\n");
    else printf("NO\n");
    return 0;
}

 

posted @ 2013-08-10 08:45  Felix_F  阅读(972)  评论(0编辑  收藏  举报