术业有专攻,想练练几何。
题目:给你一个半圆,给你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);
}
}