中石油训练赛 - Gone Fishing(固定大小的圆可以覆盖最多的点)

题目大意:在二维平面中给出 n 个点,再给出一个固定大小的圆,问如何放置这个圆可以使其覆盖最多的点

题目分析:首先不难想到一种 n^3 的做法,就是两层循环去枚举两个点,因为两个不同的点就可以确定下来两个圆了(对称的),然后对于这 2 * n * n 个圆的每一个来说,再用一层循环去枚举 n 个点,计算一下有多少个点可以被覆盖到就可以了

考虑优化,假如分别以点 i 和点 j 为圆心,以 r 为半径做出两个相交的圆,比较显然的是,如果在相交的阴影部分中任选一点作为圆心,同样以 r 作为半径做圆,那么点 i 和点 j 都可以同时被覆盖到,如下图所示:

所以我们不妨映射到其中一个圆的弧上,称这一段为相交弧,这样一来此题就得以优化了:

先用一层循环去固定点 i 作为圆心,然后枚举点 j 同样也作为圆心,两个圆若能相交的话求出相交弧,最多有 n 段相交弧,对于以点 i 为圆心的圆周来说,其中某个点被覆盖的次数,就是以该点为圆心所能覆盖的点数,所以求出被覆盖最多的位置即可

如何去求这个位置呢?利用差分的思想,对 n 段相交弧,也就是 2 * n 个交点进行极角排序,然后扫一遍求最大连续子段和就是答案了,时间复杂度为 n^2logn

很让人烦心的一点是,这个题目用 atan2 的极角排序很轻松 AC,但用叉积排序总是多多少少会出现一些不可描述的问题,一直卡在 97 分的位置,纠结三天了,没精力再耗下去了。。就这样随缘吧

代码:

n^3

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
   
typedef long long LL;
   
typedef unsigned long long ull;
   
const int inf=0x3f3f3f3f;
 
const int N=110;
// `计算几何模板`
const double eps = 1e-8;
const double pi = acos(-1.0);
const int maxp = 1010;
//`Compares a double to zero`
int sgn(double x){
    if(fabs(x) < eps)return 0;
    if(x < 0)return -1;
    else return 1;
}
struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){
        x = _x;
        y = _y;
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    void output(){
        printf("%.2f %.2f\n",x,y);
    }
    bool operator == (Point b)const{
        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
    }
    bool operator < (Point b)const{
        return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x;
    }
    Point operator -(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    //叉积
    double operator ^(const Point &b)const{
        return x*b.y - y*b.x;
    }
    //点积
    double operator *(const Point &b)const{
        return x*b.x + y*b.y;
    }
    //返回长度
    double len(){
        return hypot(x,y);//库函数
    }
    //返回两点的距离
    double distance(Point p){
        return hypot(x-p.x,y-p.y);
    }
    Point operator +(const Point &b)const{
        return Point(x+b.x,y+b.y);
    }
    //`化为长度为r的向量`
    Point trunc(double r){
        double l = len();
        if(!sgn(l))return *this;
        r /= l;
        return Point(x*r,y*r);
    }
    //`逆时针旋转90度`
    Point rotleft(){
        return Point(-y,x);
    }
    //`顺时针旋转90度`
    Point rotright(){
        return Point(y,-x);
    }
}point[N];
//圆
struct circle{
    Point p;//圆心
    double r;//半径
    circle(){}
    circle(Point _p,double _r){
        p = _p;
        r = _r;
    }
    circle(double x,double y,double _r){
        p = Point(x,y);
        r = _r;
    }
    //输入
    void input(){
        p.input();
        scanf("%lf",&r);
    }
    //输出
    void output(){
        printf("%.2lf %.2lf %.2lf\n",p.x,p.y,r);
    }
    bool operator == (circle v){
        return (p==v.p) && sgn(r-v.r)==0;
    }
    bool operator < (circle v)const{
        return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));
    }
    //`点和圆的关系`
    //`0 圆外`
    //`1 圆上`
    //`2 圆内`
    int relation(Point b){
        double dst = b.distance(p);
        if(sgn(dst-r) < 0)return 2;
        else if(sgn(dst-r)==0)return 1;
        return 0;
    }
    //`两圆的关系`
    //`5 相离`
    //`4 外切`
    //`3 相交`
    //`2 内切`
    //`1 内含`
    //`需要Point的distance`
    //`测试:UVA12304`
    int relationcircle(circle v){
        double d = p.distance(v.p);
        if(sgn(d-r-v.r) > 0)return 5;
        if(sgn(d-r-v.r) == 0)return 4;
        double l = fabs(r-v.r);
        if(sgn(d-r-v.r)<0 && sgn(d-l)>0)return 3;
        if(sgn(d-l)==0)return 2;
        if(sgn(d-l)<0)return 1;
    }
    //`求两个圆的交点,返回0表示没有交点,返回1是一个交点,2是两个交点`
    //`需要relationcircle`
    //`测试:UVA12304`
    int pointcrosscircle(circle v,Point &p1,Point &p2){
        int rel = relationcircle(v);
        if(rel == 1 || rel == 5)return 0;
        double d = p.distance(v.p);
        double l = (d*d+r*r-v.r*v.r)/(2*d);
        double h = sqrt(r*r-l*l);
        Point tmp = p + (v.p-p).trunc(l);
        p1 = tmp + ((v.p-p).rotleft().trunc(h));
        p2 = tmp + ((v.p-p).rotright().trunc(h));
        if(rel == 2 || rel == 4)
            return 1;
        return 2;
    }
    //`得到过a,b两点,半径为r1的两个圆`
    static int gercircle(Point a,Point b,double r1,circle &c1,circle &c2){
        circle x(a,r1),y(b,r1);
        int t = x.pointcrosscircle(y,c1.p,c2.p);
        if(!t)return 0;
        c1.r = c2.r = r1;
        return t;
    }
};
 
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
    double r;
    scanf("%lf",&r);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        point[i].input();
    int ans=1;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            circle c1,c2;
            circle::gercircle(point[i],point[j],r,c1,c2);
            int sum1=0,sum2=0;
            for(int k=1;k<=n;k++)
            {
                if(c1.relation(point[k]))
                    sum1++;
                if(c2.relation(point[k]))
                    sum2++;
            }
            ans=max(ans,sum1);
            ans=max(ans,sum2);
        }
    printf("%d\n",ans);
 
 
 
 
 
 
 
    return 0;
}

n^2logn

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
      
typedef long long LL;
      
typedef unsigned long long ull;
      
const int inf=0x3f3f3f3f;
    
const int N=110;
 
const double eps=1e-8;
 
int sgn(double x)
{
    if(fabs(x)<=eps)
        return 0;
    if(x<0)
        return -1;
    return 1;
}
 
struct Point
{
    double x,y;
    void input()
    {
        scanf("%lf%lf",&x,&y);
    }
    double distance(const Point& t)const
    {
        return hypot(x-t.x,y-t.y);
    }
}point[N];
    
struct Node
{
    double alpha;
    int flag;
    Node(double alpha,int flag):alpha(alpha),flag(flag){}
    bool friend operator<(const Node& a,const Node& b)
    {
        if(sgn(a.alpha-b.alpha)==0)
            return a.flag>b.flag;
        return sgn(a.alpha-b.alpha)<0;
    }
};
    
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
    double r;
    scanf("%lf",&r);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
        point[i].input();
    int ans=1;
    for(int i=1;i<=n;i++)
    {
        vector<Node>node;
        for(int j=1;j<=n;j++)
        {
            if(i==j)
                continue;
            double dis=point[i].distance(point[j]);
            if(sgn(dis-2*r)>0)
                continue;
            double alpha=atan2(point[j].y-point[i].y,point[j].x-point[i].x);
            double phi=acos(dis/(2.0*r));
            node.push_back(Node(alpha-phi,1));
            node.push_back(Node(alpha+phi,-1));
        }
        sort(node.begin(),node.end());
        int sum=0;
        for(auto it:node)
        {
            sum+=it.flag;
            ans=max(ans,sum+1);
        }
    }
    printf("%d\n",ans);
    
    
    
    
    
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/109037826
今日推荐