Graham算法模板 F 题Saint John Festival 20152016-acmicpc-southwestern-europe-regional-

42 篇文章 0 订阅
27 篇文章 0 订阅

题目就是要求解有多少个点可以被至少一个三角形围住,这个点可以在三角形的边上

题解:

每一个点肯定会在最大的凸包里面,所以我们求解一个凸包,然后二分点,寻找这样的三角形即可


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

#define MAXN 10005
const double eps=1e-8;
struct Point
{
    double x,y;
    Point(){}
    Point(double _X, double _Y){
        x = _X; y = _Y;
    }
};
Point P[MAXN];
int Stack[MAXN],top;///下标从0开始计数到top

double Cross(Point p1,Point p2,Point p3){
    return (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x);
}
double Dis(Point A, Point B){
    return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}
Point operator - (Point A,Point B){
    return Point(A.x-B.x, A.y-B.y);
}
Point operator + (Point A, Point B){
    return Point(A.x+B.x, A.y+B.y);
}
Point operator * (Point A, double p){
    return Point(A.x*p, A.y*p);
}
bool operator == (Point A, Point B){
    return (A.x-B.x) == 0 && (A.y-B.y) == 0;
}
int sgn(double x)
{
    if(fabs(x)<eps)
        return 0;
    if(x<0)
        return -1;
    return 1;
}

bool cmp(Point A, Point B)///按极角升序排序,若角度相等距离小的在前面
{
    double temp = sgn(Cross(P[0],A,B));
    if(temp > 0) return true;
    else if(temp==0&&(sgn(Dis(P[0], A) - Dis(P[0], B)))<=0) return true;
    else return false;
}

void Graham(int n)
{
    double xx=P[0].x,yy=P[0].y;
    int id=0;//找到y坐标最小的点,若有多个选择x坐标最小的记录下标
    for(int i=1;i<n;i++){
        if(P[i].y<yy || (P[i].y==yy&&P[i].x<xx)){
            xx = P[i].x;
            yy = P[i].y;
            id = i;
        }
    }
    Point T=P[0];
    P[0]=P[id];
    P[id]=T;
    sort(P+1,P+n,cmp);

    if(n==1){
        top=1;
        Stack[0]=0;
        return;
    }
    if(n==2){
        top=2;
        Stack[0]=0;
        Stack[1]=1;
        return ;
    }
    Stack[0]=0;
    Stack[1]=1;
    top=2;
    for(int i=2;i<n;i++)
    {
        while(top>1&&sgn(Cross(P[Stack[top-2]],P[Stack[top-1]],P[i]))<=0)
            top--;
        Stack[top++]=i;
    }
}

bool judge(Point temp)
{
    int left,right,mid;
    double t1,t2,t3;
    left=1,right=top-2;
    while(left<=right)
    {
        mid=(left+right)/2;
        Point a=P[Stack[0]],b=P[Stack[mid]],c=P[Stack[mid+1]];
        t1=Cross(a,b,temp);
        t2=Cross(a,c,temp);
        if(t1>=0&&t2<=0){
            t3=Cross(b,c,temp);
            if(t3>=0)
                return true;
            return false;
        }
        if(t1<0)
            right=mid-1;
        else
            left=mid+1;
    }
    return false;
}

int main()
{
    int n,s;
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
            scanf("%lf%lf",&P[i].x,&P[i].y);
        Graham(n);
        scanf("%d",&s);
        int ans=0;
        Point num;
        while(s--)
        {
            scanf("%lf%lf",&num.x,&num.y);
            if(judge(num))
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值