java 单位圆_AcWing 1981. 【POJ】1981【Java】单位圆覆盖最多的点数

/**

1. 单位圆能最多覆盖多少个点

1.1 怎么判断一个点在圆内? -> 点到圆心的距离小于半径 -> eps?

1.2 怎么让点最多? -> 让尽可能多的点在圆弧上, 这样其他部分就能向外更多的扩展

2. 怎么确定一个单位圆, 如果知道在圆弧上的两个点A(x1, y1), B(x2, y2)就能唯一确定一个圆心O(x, y), 可以用向量旋转

2.1 可求出向量AB -> AB = B - A

2.2 求出角r(OAB) -> AB.length() = sqrt((x1-x2)^2 + (y1-y2)^2), cos(r) = AB.length() / 2, r = acos(cos(r))

2.3 AB旋转r(OAB)后, 得到 OA': x = x*cos(r) - y*sin(r) , y = x*sin(r) + y * cos(r)

2.3 缩放OA'长度得到 OA向量: x = x/AB.length * R , y = y/AB.length * R

2.4 OA = A - O -> O = OA+A : x += x1, y+= y1

3. 枚举每2个点构成的圆, 找出覆盖最大的一个即可 -> O(n^2) * O(n)

4. 因为 n != 0 ,所以解的最小值为1, 可能存在任意2个点都不在圆上的情况

*/

import java.util.*;

class Main{

class Point{

double x, y;

public Point(double x, double y){

this.x = x;

this.y = y;

}

}

int sgn(double x){

if (x < -EPS) return -1;

if (x > EPS) return 1;

return 0;

}

static final double EPS = 1e-8;

static final int R = 1;

void run(){

List list = new ArrayList();

while (jin.hasNext()){

list.clear();

int n = jin.nextInt();

if (n == 0) break;

for (int i = 0; i < n ; i++){

double x = jin.nextDouble();

double y = jin.nextDouble();

Point p = new Point(x, y);

list.add(p);

}

System.out.println(solve(list));

}

}

public int solve(List list){

int result = 1;

for (int i = 0; i < list.size() ; i++){

Point A = list.get(i);

for (int j = i+1; j < list.size(); j++){

Point B = list.get(j);

Point AB = new Point(B.x-A.x, B.y-A.y);

double ABlen = Math.sqrt(AB.x * AB.x + AB.y * AB.y);

if (sgn(ABlen - 2*R) > 0) continue;

double cosangle = (ABlen) / 2;

double angle = Math.acos(cosangle);

AB.x /= ABlen;

AB.y /= ABlen;

Point AO = new Point(AB.x * Math.cos(angle) - AB.y * Math.sin(angle),

AB.x * Math.sin(angle) + AB.y * Math.cos(angle));

Point O = new Point(AO.x + A.x, AO.y + A.y);

// System.out.printf(" %f, %f, %f, %f\n", cosangle, angle, AO.x, AO.y);

result = Math.max(result, cover(O, list));

}

}

return result;

}

public int cover(Point O, List list){

int count = 0;

for (int i = 0 ; i < list.size(); i++){

Point C = list.get(i);

double dx = O.x - C.x;

double dy = O.y - C.y;

double len = Math.sqrt(dx*dx + dy*dy);

if (sgn(len - R) <= 0) count ++;

}

return count;

}

private Scanner jin = new Scanner(System.in);

public static void main(String[] args) {new Main().run();}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值