League of Demacia(平面几何)

原题:Gym-101810K

题意:
这里写图片描述
你能射出一个宽度为z的气功波,杀死所有边界及边界内的敌人,问n个点中是否可以杀死至少m个点

解析:

对于每个点都作为边界进行判断

  1. 如果距离原点比较远,那么把气功波的左边界按在这个点上
  2. 如果比较近,把气功波的下边界按在这个点上

我们通过这个边界求出下边界往左方向的单位向量

  1. 判断一个点是不是在两条左右边界内:点乘是否小于等于Z/2,就是判断在下边界的投影是否超出范围
  2. 判断是不是在下边界的上侧:判断(O,P)这个向量逆时针转到单位向量的角度是否小于等于Π

注意,因为精度问题,i==j的情况要拎出来

代码:


F eps=1e-8;
const F pi=acos(-1);
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}

struct point{
    F x,y;
    point(){}
    point(F x,F y):x(x),y(y){}
};
typedef point Vector;
typedef point Point;
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);
}
int dcmp(double x){//精度三态函数(>0,<0,=0)
    if (fabs(x) < eps)return 0;
    else if (x > 0)return 1;
    return -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));
}
double Angle(Vector a, Vector b){//夹角,弧度制
    return acos(Dot(a, b) / Length(a) / Length(b));
}
double Cross(Vector a, Vector b){//外积
    return a.x*b.y - a.y*b.x;
}
Vector Rotate(Vector a, double rad){//逆时针旋转
    return Vector(a.x*cos(rad) - a.y*sin(rad), a.x*sin(rad) + a.y*cos(rad));
}
double Distance(Point a, Point b){//两点间距离
    return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}




int n,m;F z;
point p[1009],O;


int main(){
    int t=read();
    while(t--){
        scanf("%d%d%lf",&n,&m,&z);z/=2.0;
        for(int i=1;i<=n;i++){
            scanf("%lf%lf",&p[i].x,&p[i].y);
        }
        int ans=0;
        for(int i=1;i<=n;i++){

            point l=p[i];//the endpoint
            if(Length(l)>z)
                l=Rotate(l,acos(z/Length(l)));
            l=l/Length(l);

            int sum=1;
            for(int j=1;j<=n;j++)if(i!=j){
                if(z>=abs(Dot(p[j],l))){
                    if(Cross(p[j],l)>=0)sum++;
                }
            }
            ans=max(ans,sum);
        }

        if(ans>=m)printf("Yes\n");
        else printf("No\n");
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/81627450