hdu 1077 Catching Fish 计算几何(圆覆盖)
2014-08-13 12:42
295 查看
题意:
给定n个点,现在要求找一个点作为一个半径为1的圆的圆心,使得这个圆能覆盖的点个数最多,输出最多能覆盖多少个点。
题解:
我们枚举两个点,认为他们是在这个圆上,那么就能确定圆心。之后可以从所有点到圆心的距离判断覆盖情况。
证:假设现在确定了一个能覆盖最多点的圆,那么我们可以移动这个圆使得覆盖的点数不变,且至少有两个点在这个圆上。
每两个点可以确定两个圆心,但只要用一个就够了(都用两点构成向量的上方圆心或者下方圆心)。
证明:若圆可以覆盖三个以上的点(两个点不需要找圆心。。),那么任意取覆盖的最外围三个点连线得到三角形ABC。我们枚举的时候枚举AB,AC,无论是先向量上方还是下方,都必定存在一个枚举的圆心,在三角形ABC内部。也就是说只要枚举一个圆心就能确定答案了(可以减少一半的时间消耗)。
注意:两点距离大于2的可以不枚举;初始化ans=1,否则一个点的时候会出错;距离判断时可以用距离的平方判断,因为sqrt很耗时间。
最后想说一句,那些耗时200MS的代码怎么写啊。。
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/wronged.gif)
代码:
给定n个点,现在要求找一个点作为一个半径为1的圆的圆心,使得这个圆能覆盖的点个数最多,输出最多能覆盖多少个点。
题解:
我们枚举两个点,认为他们是在这个圆上,那么就能确定圆心。之后可以从所有点到圆心的距离判断覆盖情况。
证:假设现在确定了一个能覆盖最多点的圆,那么我们可以移动这个圆使得覆盖的点数不变,且至少有两个点在这个圆上。
每两个点可以确定两个圆心,但只要用一个就够了(都用两点构成向量的上方圆心或者下方圆心)。
证明:若圆可以覆盖三个以上的点(两个点不需要找圆心。。),那么任意取覆盖的最外围三个点连线得到三角形ABC。我们枚举的时候枚举AB,AC,无论是先向量上方还是下方,都必定存在一个枚举的圆心,在三角形ABC内部。也就是说只要枚举一个圆心就能确定答案了(可以减少一半的时间消耗)。
注意:两点距离大于2的可以不枚举;初始化ans=1,否则一个点的时候会出错;距离判断时可以用距离的平方判断,因为sqrt很耗时间。
最后想说一句,那些耗时200MS的代码怎么写啊。。
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/wronged.gif)
代码:
#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; }
相关文章推荐
- HDU 1077 Catching Fish(计算几何,用单位圆围尽量多的点)
- HDU--1077--Catching Fish--计算几何
- hdu 1077 Catching Fish(计算几何)
- hdu-1077-Catching Fish-计算几何、枚举圆心
- HDU 4606 Occupy Cities (计算几何+最短路+二分+最小路径覆盖)
- 计算几何 之 hdu 1077 poj 1981 O(n^2logn)
- hdu 4606 Occupy Cities - 计算几何 + 最短路 + 最小路径覆盖
- HDU - 4637(几何计算+区间覆盖)
- 计算几何 之 hdu 1077 poj 1981 O(n^3)
- HDU 4720(计算几何+最小圆覆盖)
- hdu 1077计算几何
- 计算几何 之 hdu 1077 poj 1981 O(n^2logn)
- hdu-3007(计算几何+最小覆盖圆)
- HDU 3932(计算几何+最小圆覆盖)
- HDU 3007 最小圆覆盖 计算几何
- 计算几何 之 hdu 1077 poj 1981 O(n^3)
- HDU 3007 Buried memory(计算几何の最小圆覆盖,模版题)
- HDU 5251 矩形面积 (计算几何+旋转卡壳求覆盖凸包的最小矩形面积)
- HDU2108 Shape of HDU - 计算几何 判断凹凸多边形
- Rotational Painting hdu 好的计算几何题!!