CFGYM101915 B Ali and Wi-Fi (圆+关键点)

CFGYM101915 B Ali and Wi-Fi

Mean

给定\(n\)个圆,每个圆有一个权值\(sp\)
定义一个点的权值为从覆盖了这个点的圆里选取\(m\)个圆的权值的最大累和。
求所有选点方案中的最大累和值。
\(n<=100\)

Sol

利用关键点的思想,观察到最大方案的选点可以选在圆心或者两个圆的交点上。

暴力取出这些点,点的数目数量级不超过\(n^2\),因为一个圆和另一个圆在不重合的前提下至多只有两个交点。

枚举这些点,然后暴力判断包含(包括边界)其的圆,取出他们的权值然后排序取出前\(m\)大的权值计算,最后取最大值即可

复杂度\(O(n^3logn)\),实际上跑不满。

Code

#include<bits/stdc++.h>
using namespace std;
/*
几何 + 关键点思想

给定若干个圆,每个圆有一个权值sp,
定义一个点的权值为从覆盖了这个点的圆里选取m个圆的最大累和

求所有选点方案中的最大累和值

 */
int t;
int n,m;
#define eps 1e-6
typedef double db;
const db pi=acos(-1);
inline int sgn(db x){//符号函数 0表示0,1表示正数,-1表示负数 
    if(fabs(x)<eps)return 0;
    return x>0?1:-1;
}
inline int dcmp(db x,db y){//比较x和y的大小,0:相等,1为大于,-1为小于 
    if(fabs(x-y)<eps)return 0;
    else return x<y?-1:1;
}
struct Point{
    db x,y;
    Point():x(),y(){}
    Point(db _x,db _y):x(_x),y(_y){}
    void input(){
        scanf("%lf %lf",&x,&y);
    }
}; 
typedef Point Vector;
//typedef Line Sement;
inline Vector operator+ (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);} 
inline Vector operator- (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);} 
inline Vector operator* (Vector A,db k){return Vector(A.x*k,A.y*k);}
inline Vector operator/ (Vector A,db k){return Vector(A.x/k,A.y/k);}
inline bool operator== (Point A,Point B){return dcmp(A.x,B.x)==0&&dcmp(A.y,B.y)==0;}
inline bool operator< (Point A,Point B){return A.x<B.x||(A.x==B.x&&A.y<B.y);}


inline double angle(Vector v) { return atan2(v.y, v.x); }
inline db msqrt(db x){return (x<0?0:sqrt(x));}
inline db det(Vector a,Vector b){return a.x*b.y-a.y*b.x;}// 返回两向量的叉积 
inline db Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}// 返回两向量的叉积 
inline db dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}//返回两向量的点积 
inline db Length(Vector A){return msqrt(dot(A,A));};//返回向量的长度
inline db Length2(Vector A){return dot(A,A);}//返回向量长度的平方 
inline Vector Unit(Vector x) { return x / Length(x); }  //单位向量
inline db Dist(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
inline Vector Rotate(Vector A, db rad)//逆时针旋转rad°
{
    return Vector(A.x * cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y * cos(rad));
}
struct Circle{
    Point c;db r;
    db spe;
    Circle():c(),r(),spe(){}
    Circle(Point c,db r,db spe):c(c),r(r),spe(spe){}
    inline Point point(double a) //根据圆心角求点坐标 参数方程
    {
        return Point(c.x+cos(a)*r, c.y+sin(a)*r);
    }
}c[200];

//求两个圆的交点,返回个数 
//已验证
int getCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol) {
    db d = Length(C1.c - C2.c);
    if(sgn(d) == 0) {
        if(dcmp(C1.r,C2.r) == 0) return -1; // 重合,无穷多交点
        return 0;
    }
    if(dcmp(C1.r + C2.r,d) < 0) return 0;//外离
    if(dcmp(fabs(C1.r-C2.r),d) > 0) return 0;//内含
    db rad = angle(C2.c - C1.c);
    Vector v = Vector(C2.c-C1.c);
    db da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));
    Point p1 = C1.c+Rotate(Unit(v)*C1.r,da), p2 =C1.c+Rotate(Unit(v)*C1.r,-da);//向量加法 OC+CP=OP P为交点
    sol.push_back(p1);
    //if(p1 == p2) return 1;
    sol.push_back(p2);
    return 2;
}

//点与圆的位置关系
inline int Point_Circle_relation(Point p,Circle C){
    db dst=Dist(p,C.c);
    if(dcmp(dst,C.r)<0)return 0;//0:点在园内
    else if(dcmp(dst,C.r)==0)return 1;//1:点在圆上
    return 2;//2:点在园外
}

bool cmp(Point a,Point b){
    if(a.x==b.x){
        return a.y<b.y;
    }
    return a.x<b.x;
}
int main(){
    cin>>t;
    while(t--){
        cin>>n>>m;
        for(int i=1;i<=n;++i){
            db x,y,r,sp;
            cin>>x>>y>>r>>sp;
            c[i]=Circle(Point(x,y),r,sp);
        }   
        vector<Point>kep,ins;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                //if(i==j)continue;
                vector<Point>vp;
                int val=getCircleCircleIntersection(c[i],c[j],vp);
                if(val==0||val==-1){
                    kep.push_back(c[i].c);
                }
                else if(val!=0&&val!=-1){
                    kep.push_back(vp[0]);
                    kep.push_back(vp[1]);   
                }
            }
        }
        sort(kep.begin(),kep.end(),cmp);
        for(int i=0;i<(int)kep.size();++i){
            int pos = i;
            while(pos<(int)kep.size()&&kep[pos]==kep[i]){
                pos++;
            }
            ins.push_back(kep[i]);
            i=pos-1;
        }
        int mx=0;

        vector<int>ssp;
        for(int i=0;i<(int)ins.size();++i){
            ssp.clear();
            for(int j=1;j<=n;++j){
                if(Point_Circle_relation(ins[i],c[j])<=1){
                    ssp.push_back(c[j].spe);
                }
            }
            sort(ssp.begin(), ssp.end());
            int cnt=m;
            int sum=0;
            for(int j=(int)ssp.size()-1;j>=0&&cnt;j--){
                sum+=ssp[j];
                cnt--;
            }
            mx=max(mx,sum);
        }
        printf("%d\n",mx);
    }
    return 0;
}
posted @ 2021-10-18 16:47  Qquun  阅读(60)  评论(0)    收藏  举报