您的位置:首页 > 其它

hdu 1077 Catching Fish 计算几何(圆覆盖)

2014-08-13 12:42 295 查看
题意:

给定n个点,现在要求找一个点作为一个半径为1的圆的圆心,使得这个圆能覆盖的点个数最多,输出最多能覆盖多少个点。

题解:

我们枚举两个点,认为他们是在这个圆上,那么就能确定圆心。之后可以从所有点到圆心的距离判断覆盖情况。

证:假设现在确定了一个能覆盖最多点的圆,那么我们可以移动这个圆使得覆盖的点数不变,且至少有两个点在这个圆上。

每两个点可以确定两个圆心,但只要用一个就够了(都用两点构成向量的上方圆心或者下方圆心)。

证明:若圆可以覆盖三个以上的点(两个点不需要找圆心。。),那么任意取覆盖的最外围三个点连线得到三角形ABC。我们枚举的时候枚举AB,AC,无论是先向量上方还是下方,都必定存在一个枚举的圆心,在三角形ABC内部。也就是说只要枚举一个圆心就能确定答案了(可以减少一半的时间消耗)。

注意:两点距离大于2的可以不枚举;初始化ans=1,否则一个点的时候会出错;距离判断时可以用距离的平方判断,因为sqrt很耗时间。

最后想说一句,那些耗时200MS的代码怎么写啊。。


代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;

const int maxn=303;
const double pi=atan(1.0)*4;
const double len=1.0001*1.0001;
//基础点和向量运算
struct Point{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);}
bool operator <(const Point& a, const Point& b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double eps=1e-6;
int dcmp(double x)//判断正负,或者等于0
{
    if(fabs(x)<eps)return 0;else return x<0?-1:1;
}
bool operator==(const Point& a,const Point &b)
{
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Dot(Vector A, Vector B){return A.x*B.x+A.y*B.y;}//点积
double Length(Vector A){return sqrt(Dot(A,A));}//OA长
double Angle(Vector A,Vector B){return acos(Dot(A,B)/Length(A)/Length(B));}//OA和OB的夹角
double Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//叉积
double Area2(Point A,Point B,Point C){return Cross(B-A,C-A);}//三角形面积
Vector Rotate(Vector A,double rad)//rad为弧度,旋转rad度
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A)//A的单位法向量,A不能为零向量
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}
Point e[maxn];
int ans;
int get_cover_num(Point a,Point b,int n)
{
    Point f1,f2,d1,d2,c;
    c=Point((a.x+b.x)/2,(a.y+b.y)/2);
    double L=Length(b-a);
    f1=Normal(b-a);
    f2=Normal(a-b);
    //找到圆心
    d1=c+f1*sqrt(1.0-L*L/4);
    d2=c+f2*sqrt(1.0-L*L/4);
    int i,num1=0,num2=0;
    //省略一个圆心判断,可以减少一半的时间
    for(i=0;i<n;i++)
    {
        if(dcmp(Dot(d1-e[i],d1-e[i])-len)<=0)num1++;
        //if(dcmp(Dot(d2-e[i],d2-e[i])-len)<=0)num2++;
    }
    return max(num1,num2);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k,n;
        scanf("%d",&n);
        for(i=0;i<n;i++)
            scanf("%lf%lf",&e[i].x,&e[i].y);
        ans=1;
        for(i=0;i<n;i++)
        {
            for(j=i+1;j<n;j++)
            {
                if(dcmp(Dot(e[i]-e[j],e[i]-e[j])-4.0)>0)continue;
                ans=max(ans,get_cover_num(e[i],e[j],n));
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: