POJ1106 (极角排序)

术业有专攻,想练练几何。
题目:给你一个半圆,给你n个点,问半圆最大能覆盖几个点。
题解:第一次做平面几何确实没什么思路,转换一下,先把整个圆外的点给去除,再枚举任意一个点,和圆心连成一条直线,(想像一下如果最优解的直径除了圆心没有经过一个点,你转过去一定角度直至经过一个点是不影响结果的)那么圆就分成两个半圆了,用叉积判断点与直线的位置,取较大值就可以了
还需要考虑如下情况:1、有些点与圆心重合。 2、同时有多个点在一条直线上


#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define fuck() (cout << " ------------------ " << endl)
const int maxn = 100000 + 5;
using namespace std;
struct Point{
    double x,y;
    Point(){}
    Point(double x_, double y_):x(x_),y(y_){}
}pt[maxn];
bool judge(double x1, double y1, double x2, double y2, double r){
    if( (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) <= r*r)
        return true;
    return false;
}
double cross(Point a, Point b, Point c){
    return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
double atleft(Point a, Point b, Point c){
    return cross(a,b,c);
}
int main(){
    double cx, cy;
    double r;
    while(scanf("%lf%lf%lf",&cx,&cy,&r) == 3 && r>0){
        int n;
        scanf("%d",&n);
        int ans = 0;
        int cnt = 0;
        int sum = 0;
        for(int i=0; i<n; i++){
            int x, y;
            scanf("%d%d",&x,&y);
            if(x == cx && y == cy){
                ans++;
                sum++;
                continue;
            }
            if(judge(x,y,cx,cy,r)){
                pt[cnt++] = Point(x,y);
            }
        }
        pt[cnt] = Point(cx,cy);
        for(int i=0; i<cnt; i++){
            int left = 0;
            int right = 0;
            for(int j=0; j<cnt; j++){
                if(i == j) continue;
                double ok = atleft(pt[i],pt[cnt],pt[j]);
                if(ok == 0){
                    left++;
                    right++;
                }
                else if(ok > 0)
                    left++;
                else right++;
            }
            ans = max(ans, sum + left + 1);
            ans = max(ans, sum + right + 1);
        }
        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值