HDU 1077 Catching Fish(计算几何,用单位圆围尽量多的点)

 

Catching Fish

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 943    Accepted Submission(s): 335

Problem Description Ignatius likes catching fish very much. He has a fishnet whose shape is a circle of radius one. Now he is about to use his fishnet to catch fish. All the fish are in the lake, and we assume all the fish will not move when Ignatius catching them. Now Ignatius wants to know how many fish he can catch by using his fishnet once. We assume that the fish can be regard as a point. So now the problem is how many points can be enclosed by a circle of radius one.

Note: If a fish is just on the border of the fishnet, it is also caught by Ignatius.  

 

Input The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.

Each test case starts with a positive integer N(1<=N<=300) which indicate the number of fish in the lake. Then N lines follow. Each line contains two floating-point number X and Y (0.0<=X,Y<=10.0). You may assume no two fish will at the same point, and no two fish are closer than 0.0001, no two fish in a test case are approximately at a distance of 2.0. In other words, if the distance between the fish and the centre of the fishnet is smaller 1.0001, we say the fish is also caught.  

 

Output For each test case, you should output the maximum number of fish Ignatius can catch by using his fishnet once.  

 

Sample Input 4 3 6.47634 7.69628 5.16828 4.79915 6.69533 6.20378 6 7.15296 4.08328 6.50827 2.69466 5.91219 3.86661 5.29853 4.16097 6.10838 3.46039 6.34060 2.41599 8 7.90650 4.01746 4.10998 4.18354 4.67289 4.01887 6.33885 4.28388 4.98106 3.82728 5.12379 5.16473 7.84664 4.67693 4.02776 3.87990 20 6.65128 5.47490 6.42743 6.26189 6.35864 4.61611 6.59020 4.54228 4.43967 5.70059 4.38226 5.70536 5.50755 6.18163 7.41971 6.13668 6.71936 3.04496 5.61832 4.23857 5.99424 4.29328 5.60961 4.32998 6.82242 5.79683 5.44693 3.82724 6.70906 3.65736 7.89087 5.68000 6.23300 4.59530 5.92401 4.92329 6.24168 3.81389 6.22671 3.62210  

 

Sample Output 2 5 5 11  

 

Author Ignatius.L       简单的计算几何题。 枚举两个点来确定圆心,然后求解。 但是注意N==1的时候,一定要保证输出是1,这里WA了很久。   两个程序,一个用结构体,一个用数组,用数组的要快很多。    

/*
HDU 1077
题意:给出一些点坐标,问有一个半径为1的圆,一次最多能圈多小个点;

枚举两个点确定圆心,然后求解
O(n^3)
G++ 2515ms
*/
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<iostream>
using namespace std;

const int MAXN=330;
const double eps=1e-4;

struct Point
{
    double x,y;
}point[MAXN];

double dis(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}



Point center1,center2;//根据两个点确定的圆心

void get_center_point(Point a,Point b)//根据两个点确定圆心,保证两点的距离不大于2,圆的半径为1
{
    double x0=(a.x+b.x)/2;
    double y0=(a.y+b.y)/2;

    double d=sqrt(1-((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))/4);//圆心到中点的距离
    if(fabs(a.y-b.y)<1e-6)
    {
        center1.x=x0;
        center1.y=y0+d;
        center2.x=x0;
        center2.y=y0-d;
    }
    else
    {
        double tmp=atan(-(a.x-b.x)/(a.y-b.y));
        double dx=d*cos(tmp);
        double dy=d*sin(tmp);
        center1.x=x0+dx;
        center1.y=y0+dy;
        center2.x=x0-dx;
        center2.y=y0-dy;
    }
}

int main()
{
    int T;
    int n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
          scanf("%lf%lf",&point[i].x,&point[i].y);
        int ans=1;//注意一个点的情况,所以初值应该给0,否则会一只wa的。
        for(int i=0;i<n;i++)
          for(int j=i+1;j<n;j++)
          {
              if(dis(point[i],point[j])>2.0)continue;
              get_center_point(point[i],point[j]);
              int cnt=2;
              for(int t=0;t<n;t++)
                if(t!=i&&t!=j&&dis(point[t],center1)<1+eps)
                  cnt++;
              if(cnt>ans)ans=cnt;
              cnt=2;
              for(int t=0;t<n;t++)
                if(t!=i&&t!=j&&dis(point[t],center2)<1+eps)
                  cnt++;
              if(cnt>ans)ans=cnt;
          }
        printf("%d\n",ans);
    }
    return 0;
}

 

 

/*
HDU 1077
题意:给出一些点坐标,问有一个半径为1的圆,一次最多能圈多小个点;

枚举两个点确定圆心,然后求解
O(n^3)
用数组实现,更节约时间
G++ 968ms

*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
const int MAXN=330;
const double eps=1e-4;

double p[MAXN][2];
double xx1,yy1,xx2,yy2;

double dis(int i,int j)
{
    return sqrt((p[i][0]-p[j][0])*(p[i][0]-p[j][0])+(p[i][1]-p[j][1])*(p[i][1]-p[j][1]));
}

void get_center_point(int a,int b)
{
    double x0=(p[a][0]+p[b][0])/2;
    double y0=(p[a][1]+p[b][1])/2;
    double d=sqrt(1-((p[a][0]-p[b][0])*(p[a][0]-p[b][0])+(p[a][1]-p[b][1])*(p[a][1]-p[b][1]))/4);
    if(fabs(p[a][1]-p[b][1])<1e-6)
    {
        xx1=x0;
        yy1=y0+d;
        xx2=x0;
        yy2=y0-d;
    }
    else
    {
        double tmp=atan(-(p[a][0]-p[b][0])/(p[a][1]-p[b][1]));
        double dx=d*cos(tmp);
        double dy=d*sin(tmp);
        xx1=x0+dx;
        yy1=y0+dy;
        xx2=x0-dx;
        yy2=y0-dy;
    }
}

int main()
{
    int T;
    int n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
           scanf("%lf%lf",&p[i][0],&p[i][1]);
        int ans=1;
        for(int i=0;i<n;i++)
          for(int j=i+1;j<n;j++)
          {
              if(dis(i,j)>2.0)continue;
              get_center_point(i,j);
              int cnt=0;
              for(int i=0;i<n;i++)
                if(sqrt((p[i][0]-xx1)*(p[i][0]-xx1)+(p[i][1]-yy1)*(p[i][1]-yy1))<1+eps)
                  cnt++;
              if(cnt>ans)ans=cnt;
              cnt=0;
              for(int i=0;i<n;i++)
                if(sqrt((p[i][0]-xx2)*(p[i][0]-xx2)+(p[i][1]-yy2)*(p[i][1]-yy2))<1+eps)
                  cnt++;
              if(cnt>ans)ans=cnt;
          }
        printf("%d\n",ans);
    }
    return 0;
}

 

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/kuangbin/archive/2012/10/20/2732091.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞