2017 CCPC秦皇岛 M题 Safest Buildings

2023-03-15,,

PUBG is a multiplayer online battle royale video game. In the game, up to one hundred players parachute onto an island and scavenge for weapons and equipment to kill others while avoiding getting killed themselves. BaoBao is a big fan of the game, but this time he is having some trouble selecting the safest building.

There are  buildings scattering on the island in the game, and we consider these buildings as points on a two-dimensional plane. At the beginning of each round, a circular safe area whose center is located at (0, 0) with radius  will be spawned on the island. After some time, the safe area will shrink down towards a random circle with radius  (). The whole new safe area is entirely contained in the original safe area (may be tangent to the original safe area), and the center of the new safe area is uniformly chosen within the original safe area.

The buildings covered by the new safe area is called the safe buildings. Given the radius of the safe areas and the positions of the buildings, BaoBao wants to find all the buildings with the largest probability to become safe buildings.

Input

There are multiple test cases. The first line of input contains an integer , indicating the number of test cases. For each test case:

The first line contains three integers  (),  and  (), indicating the number of buildings and the radius of two safe circles.

The following  lines each contains 2 integers  and  (), indicating the coordinate of the buildings. Here we assume that the center of the original safe circle is located at , and all the buildings are inside the original circle.

It's guaranteed that the sum of  over all test cases will not exceed 5000.

<h4< dd="">Output

For each test case output two lines.

The first line contains an integer , indicating the number of buildings with the highest probability to become safe buildings.

The second line contains  integers separated by a space in ascending order, indicating the indices of safest buildings.

Please, DO NOT output extra spaces at the end of each line.

<h4< dd="">Sample Input

2
3 10 5
3 4
3 5
3 6
3 10 4
-7 -6
4 5
5 4

<h4< dd="">Sample Output

1
1
2
2 3
题解:

给一个大圈半径,圆心在原点,再给一个小圆半径,再给出一些点的左边,小圆在大圆中任意一个可以出现的位置的概率相同,小圆必须被大圆完全覆盖,问那些点被小圆覆盖的几率最大。因为一开始读错题以为求小圆最多能覆盖多少个点,但其实并没有那么难,只要找到某个点能被小圆覆盖的最大范围即可,即以点为小圆的边上一点,围绕这个点转一个圈即可,即以某一点为圆心,以小圆直径为半径画圆的面积与大圆面积的交面积与大圆的比值即为被覆盖到的概率,全部求出来排序即可。

参考代码:
 //计算几何模板,二维几何基础
//使用印用注意避免直接在程序中调用构造函数构造无名对象。否则可能会导致程序出错
#include <bits/stdc++.h>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <set>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <map>
#include <string>
#define INF 0x3f3f3f3f
#define rep(i,a,n) for(int i=a;i<n;++i)
#define per(i,a,n) for(int i=n-1;i>=a;--i)
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
const double eps =1e-;
const int maxn=; //注意修改
int n,t;
//有的命名为sgn函数,高精度符号判断
int dcmp(double x){
//相等函数判断,减少精度问题
if(fabs(x)<eps) return ;
else return x<?-:;
} //点的定义
class Point{
public:
double x,y;
Point (double x=,double y=):x(x),y(y){} //构造函数,方便代码的编写
}point[maxn],pafter[maxn]; typedef Point Vector;// 从程序实现上,Vector只是Point的别名 //运算符重载
Vector operator + (const Vector &A,const Vector &B) { return Vector(A.x+B.x,A.y+B.y); } //向量+向量=向量,点+向量=点
Vector operator - (const Vector &A,const Vector &B) { return Vector(A.x-B.x,A.y-B.y); } //向量-向量=向量,点-向量-点
Vector operator * (const Vector &A,double p) { return Vector(A.x*p,A.y*p); } //向量*数=向量 (数乘)
Vector operator / (const Vector &A,double p) { return Vector(A.x/p,A.y/p); } //向量/数=向量 (数除)
double operator * (const Vector &A,const Vector &B) { return A.x*B.x+A.y*B.y; } //向量(点乘)向量=数 (点乘)
bool operator < (const Point &A,const Point &B) { return A.x==B.x?A.y<B.y:A.x<B.x; } //按x值递增排序
bool operator == (const Point &A,const Point &B) { return dcmp(A.x-B.x)==&& dcmp(A.y-B.y)==; } //判定两个点是否相同,用到dcmp精度判定 //点乘叉乘
double dot(const Vector &A,const Vector &B){ return A.x*B.x+A.y*B.y; } //向量(叉乘)向量=向量 (叉乘)
double operator ^ (const Vector &A,const Vector &B){ return A.x*B.y-A.y*B.x; }
double cross(const Vector &A,const Vector &B){ return A.x*B.y-A.y*B.x; } //模长面积
double abs(const Vector &A){ return sqrt(dot(A,A));} //计算向量模长
double area2(const Point &A,const Point &B,const Point &C){ return cross(B-A,C-A) ;} //计算平行四边形方向面积
double PolygonArea(Point *p,int n) { double area=; rep(i,,n-){area+=cross(p[i]-p[],p[i+]-p[]);}return area/2.0; } //计算多边形的有向面积 //旋转
Vector rotate(Vector A,double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));} //旋转rad弧度
Vector normal(Vector A){double l=abs(A);return Vector(-A.y/l,A.x/l);} //计算单位法线,左转90
double torad(double deg) { return deg/*acos(-); } //角度转弧度 //线段定义
class Line {
public:
Point s,e;
Line(){}
Line(Point _s,Point _e){
s=_s;e=_e;
} }line[maxn];
//判断两线段是否相交
bool inter(Line l1,Line l2){
// cout<<"L1 "<<l1.e.x<<","<<l1.e.y<<" "<<l1.s.x<<","<<l1.s.y<<endl;
// cout<<"L2 "<<l2.e.x<<","<<l2.e.y<<" "<<l2.s.x<<","<<l2.s.y<<endl;
return (
//根据题目要求端点相交是否算作相交来决定大于等于和小于等于
//排斥实验
max(l1.s.x,l1.e.x)>=min(l2.s.x,l2.e.x) &&
max(l2.s.x,l2.e.x)>=min(l1.s.x,l1.e.x) &&
max(l1.s.y,l1.e.y)>=min(l2.s.y,l2.e.y) &&
max(l2.s.y,l2.e.y)>=min(l1.s.y,l1.e.y) &&
//跨立实验
dcmp((l2.s-l1.s)^(l1.s-l1.e))*dcmp((l2.e-l1.s)^(l1.s-l1.e))< &&
dcmp((l1.s-l2.s)^(l2.s-l2.e))*dcmp((l1.e-l2.s)^(l2.s-l2.e))<
) ;
}
bool inter(Point a1,Point a2,Point b1,Point b2){
Line l1(a1,a2),l2(b1,b2);
return inter(l1,l2);
}
bool cmp(Point a,Point b){
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
} //求两直线交点
Point getinter(Line l1,Line l2){Vector v=l1.s-l1.e;Vector w=l2.s-l2.e;Vector u=l1.e-l2.e;double t=cross(w,u)/cross(v,w);return l1.e+v*t;}
Point getinter(Point a1,Point a2,Point b1,Point b2){Line l1(a1,a2);Line l2(b1,b2);return getinter(l1,l2);} //判定点和线段的关系,
//0:不在线段所在直线上
//1:在线段内(不含端点)
//2:在线段端点
//3:在线段两侧的射线上
int online(Point a,Line l){
if(dcmp(cross(l.s-a,l.e-a))!=) return ;
double pans=dcmp(dot(l.s-a,l.e-a));
// cout<<(l.s-a).x<<","<<(l.s-a).y<<" "<<(l.e-a).x<<","<<(l.e-a).y<<endl;
if(pans<) return ;
else if(pans==) return ;
else if(pans>) return ;
}
int online(Point a,Point b1,Point b2){
Line l(b1,b2);
return online(a,l);
} //凸包
int ConvexHull(Point *p,int n,Point *ch)
{
sort(p,p+n,cmp);
int m=;
for(int i=;i<n;i++){
while(m> && cross(ch[m-]-ch[m-],p[i]-ch[m-])<=) m--;
ch[m++]=p[i];
}
int k=m;
for(int i=n-;i>=;i--){
while(m>k && cross(ch[m-]-ch[m-],p[i]-ch[m-])<=) m--;
ch[m++]=p[i];
}
if(n>) m--;
return m;
} Point p[];
double RR,rr;
bool cmp1( pair<double,int> a, pair<double,int> b){
if(dcmp(a.first-b.first)!=) return a.first<b.first;
else return a.second<b.second;
}
int ans[];
vector< pair<double,int> > v;
int main(){
ios::sync_with_stdio(false);
cin>>t;
while(t--){
v.clear();
cin>>n;
cin>>RR>>rr;
rep(i,,n+){
cin>>p[i].x>>p[i].y;
double temp=p[i].x*p[i].x+p[i].y*p[i].y;
v.push_back(mp(temp,i));
}
sort(v.begin(),v.end(),cmp1);
// cout<<"#test"<<endl;
// rep(i,0,n){
// cout<<"dis="<<v[i].first<<" i="<<v[i].second<<endl;
// }
// p p0=p(0,0);
if(2.0*rr>RR){
//必存在安全圈
double bonder=(2.0*rr-RR)*(2.0*rr-RR);
int cnt1=;
if(v[].fi<=bonder){
rep(i,,n){
if(v[i].fi>bonder) break;
ans[cnt1++]=v[i].second;
}
sort(ans,ans+cnt1);
}
else{
bonder=v[].fi;
rep(i,,n){
if(v[i].fi>bonder+eps) break;
ans[cnt1++]=v[i].second;
}
sort(ans,ans+cnt1); }
cout<<cnt1<<endl;
cout<<ans[];
rep(i,,cnt1){
cout<<" "<<ans[i];
}
cout<<endl;
}
else {
double bonder=(RR-2.0*rr)*(RR-2.0*rr);
int cnt1=;
if(v[].fi<=bonder){
rep(i,,n){
if(v[i].fi>bonder) break;
ans[cnt1++]=v[i].second;
}
sort(ans,ans+cnt1);
}
else{
bonder=v[].fi;
rep(i,,n){
if(v[i].fi>bonder+eps) break;
ans[cnt1++]=v[i].second;
}
sort(ans,ans+cnt1); }
cout<<cnt1<<endl;
cout<<ans[];
rep(i,,cnt1){
cout<<" "<<ans[i];
}
cout<<endl;
} }
}

  

2017 CCPC秦皇岛 M题 Safest Buildings的相关教程结束。

《2017 CCPC秦皇岛 M题 Safest Buildings.doc》

下载本文的Word格式文档,以方便收藏与打印。