2017 CCPC秦皇岛 M题 Safest Buildings
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
题解:
给一个大圈半径,圆心在原点,再给一个小圆半径,再给出一些点的左边,小圆在大圆中任意一个可以出现的位置的概率相同,小圆必须被大圆完全覆盖,问那些点被小圆覆盖的几率最大。因为一开始读错题以为求小圆最多能覆盖多少个点,但其实并没有那么难,只要找到某个点能被小圆覆盖的最大范围即可,即以点为小圆的边上一点,围绕这个点转一个圈即可,即以某一点为圆心,以小圆直径为半径画圆的面积与大圆面积的交面积与大圆的比值即为被覆盖到的概率,全部求出来排序即可。
参考代码:
1 //计算几何模板,二维几何基础 2 //使用印用注意避免直接在程序中调用构造函数构造无名对象。否则可能会导致程序出错 3 #include <bits/stdc++.h> 4 #include <cstdio> 5 #include <cmath> 6 #include <cstdlib> 7 #include <cstring> 8 #include <iostream> 9 #include <set> 10 #include <iomanip> 11 #include <algorithm> 12 #include <queue> 13 #include <map> 14 #include <string> 15 #define INF 0x3f3f3f3f 16 #define rep(i,a,n) for(int i=a;i<n;++i) 17 #define per(i,a,n) for(int i=n-1;i>=a;--i) 18 #define fi first 19 #define se second 20 #define mp make_pair 21 #define pb push_back 22 using namespace std; 23 typedef long long ll; 24 const double eps =1e-10; 25 const int maxn=2500; //注意修改 26 int n,t; 27 //有的命名为sgn函数,高精度符号判断 28 int dcmp(double x){ 29 //相等函数判断,减少精度问题 30 if(fabs(x)<eps) return 0; 31 else return x<0?-1:1; 32 } 33 34 //点的定义 35 class Point{ 36 public: 37 double x,y; 38 Point (double x=0,double y=0):x(x),y(y){} //构造函数,方便代码的编写 39 }point[maxn],pafter[maxn]; 40 41 typedef Point Vector;// 从程序实现上,Vector只是Point的别名 42 43 //运算符重载 44 Vector operator + (const Vector &A,const Vector &B) { return Vector(A.x+B.x,A.y+B.y); } //向量+向量=向量,点+向量=点 45 Vector operator - (const Vector &A,const Vector &B) { return Vector(A.x-B.x,A.y-B.y); } //向量-向量=向量,点-向量-点 46 Vector operator * (const Vector &A,double p) { return Vector(A.x*p,A.y*p); } //向量*数=向量 (数乘) 47 Vector operator / (const Vector &A,double p) { return Vector(A.x/p,A.y/p); } //向量/数=向量 (数除) 48 double operator * (const Vector &A,const Vector &B) { return A.x*B.x+A.y*B.y; } //向量(点乘)向量=数 (点乘) 49 bool operator < (const Point &A,const Point &B) { return A.x==B.x?A.y<B.y:A.x<B.x; } //按x值递增排序 50 bool operator == (const Point &A,const Point &B) { return dcmp(A.x-B.x)==0&& dcmp(A.y-B.y)==0; } //判定两个点是否相同,用到dcmp精度判定 51 52 //点乘叉乘 53 double dot(const Vector &A,const Vector &B){ return A.x*B.x+A.y*B.y; } //向量(叉乘)向量=向量 (叉乘) 54 double operator ^ (const Vector &A,const Vector &B){ return A.x*B.y-A.y*B.x; } 55 double cross(const Vector &A,const Vector &B){ return A.x*B.y-A.y*B.x; } 56 57 //模长面积 58 double abs(const Vector &A){ return sqrt(dot(A,A));} //计算向量模长 59 double area2(const Point &A,const Point &B,const Point &C){ return cross(B-A,C-A) ;} //计算平行四边形方向面积 60 double PolygonArea(Point *p,int n) { double area=0; rep(i,1,n-1){area+=cross(p[i]-p[0],p[i+1]-p[0]);}return area/2.0; } //计算多边形的有向面积 61 62 //旋转 63 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弧度 64 Vector normal(Vector A){double l=abs(A);return Vector(-A.y/l,A.x/l);} //计算单位法线,左转90 65 double torad(double deg) { return deg/180*acos(-1); } //角度转弧度 66 67 //线段定义 68 class Line { 69 public: 70 Point s,e; 71 Line(){} 72 Line(Point _s,Point _e){ 73 s=_s;e=_e; 74 } 75 76 }line[maxn]; 77 //判断两线段是否相交 78 bool inter(Line l1,Line l2){ 79 // cout<<"L1 "<<l1.e.x<<","<<l1.e.y<<" "<<l1.s.x<<","<<l1.s.y<<endl; 80 // cout<<"L2 "<<l2.e.x<<","<<l2.e.y<<" "<<l2.s.x<<","<<l2.s.y<<endl; 81 return ( 82 //根据题目要求端点相交是否算作相交来决定大于等于和小于等于 83 //排斥实验 84 max(l1.s.x,l1.e.x)>=min(l2.s.x,l2.e.x) && 85 max(l2.s.x,l2.e.x)>=min(l1.s.x,l1.e.x) && 86 max(l1.s.y,l1.e.y)>=min(l2.s.y,l2.e.y) && 87 max(l2.s.y,l2.e.y)>=min(l1.s.y,l1.e.y) && 88 //跨立实验 89 dcmp((l2.s-l1.s)^(l1.s-l1.e))*dcmp((l2.e-l1.s)^(l1.s-l1.e))<0 && 90 dcmp((l1.s-l2.s)^(l2.s-l2.e))*dcmp((l1.e-l2.s)^(l2.s-l2.e))<0 91 ) ; 92 } 93 bool inter(Point a1,Point a2,Point b1,Point b2){ 94 Line l1(a1,a2),l2(b1,b2); 95 return inter(l1,l2); 96 } 97 bool cmp(Point a,Point b){ 98 if(a.x==b.x) return a.y<b.y; 99 else return a.x<b.x; 100 } 101 102 //求两直线交点 103 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;} 104 Point getinter(Point a1,Point a2,Point b1,Point b2){Line l1(a1,a2);Line l2(b1,b2);return getinter(l1,l2);} 105 106 107 //判定点和线段的关系, 108 //0:不在线段所在直线上 109 //1:在线段内(不含端点) 110 //2:在线段端点 111 //3:在线段两侧的射线上 112 int online(Point a,Line l){ 113 if(dcmp(cross(l.s-a,l.e-a))!=0) return 0; 114 double pans=dcmp(dot(l.s-a,l.e-a)); 115 // cout<<(l.s-a).x<<","<<(l.s-a).y<<" "<<(l.e-a).x<<","<<(l.e-a).y<<endl; 116 if(pans<0) return 1; 117 else if(pans==0) return 2; 118 else if(pans>0) return 3; 119 } 120 int online(Point a,Point b1,Point b2){ 121 Line l(b1,b2); 122 return online(a,l); 123 } 124 125 //凸包 126 int ConvexHull(Point *p,int n,Point *ch) 127 { 128 sort(p,p+n,cmp); 129 int m=0; 130 for(int i=0;i<n;i++){ 131 while(m>1 && cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--; 132 ch[m++]=p[i]; 133 } 134 int k=m; 135 for(int i=n-2;i>=0;i--){ 136 while(m>k && cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--; 137 ch[m++]=p[i]; 138 } 139 if(n>1) m--; 140 return m; 141 } 142 143 144 Point p[105]; 145 double RR,rr; 146 bool cmp1( pair<double,int> a, pair<double,int> b){ 147 if(dcmp(a.first-b.first)!=0) return a.first<b.first; 148 else return a.second<b.second; 149 } 150 int ans[105]; 151 vector< pair<double,int> > v; 152 int main(){ 153 ios::sync_with_stdio(false); 154 cin>>t; 155 while(t--){ 156 v.clear(); 157 cin>>n; 158 cin>>RR>>rr; 159 rep(i,1,n+1){ 160 cin>>p[i].x>>p[i].y; 161 double temp=p[i].x*p[i].x+p[i].y*p[i].y; 162 v.push_back(mp(temp,i)); 163 } 164 sort(v.begin(),v.end(),cmp1); 165 // cout<<"#test"<<endl; 166 // rep(i,0,n){ 167 // cout<<"dis="<<v[i].first<<" i="<<v[i].second<<endl; 168 // } 169 // p p0=p(0,0); 170 if(2.0*rr>RR){ 171 //必存在安全圈 172 double bonder=(2.0*rr-RR)*(2.0*rr-RR); 173 int cnt1=0; 174 if(v[0].fi<=bonder){ 175 rep(i,0,n){ 176 if(v[i].fi>bonder) break; 177 ans[cnt1++]=v[i].second; 178 } 179 sort(ans,ans+cnt1); 180 } 181 else{ 182 bonder=v[0].fi; 183 rep(i,0,n){ 184 if(v[i].fi>bonder+eps) break; 185 ans[cnt1++]=v[i].second; 186 } 187 sort(ans,ans+cnt1); 188 189 } 190 cout<<cnt1<<endl; 191 cout<<ans[0]; 192 rep(i,1,cnt1){ 193 cout<<" "<<ans[i]; 194 } 195 cout<<endl; 196 } 197 else { 198 double bonder=(RR-2.0*rr)*(RR-2.0*rr); 199 int cnt1=0; 200 if(v[0].fi<=bonder){ 201 rep(i,0,n){ 202 if(v[i].fi>bonder) break; 203 ans[cnt1++]=v[i].second; 204 } 205 sort(ans,ans+cnt1); 206 } 207 else{ 208 bonder=v[0].fi; 209 rep(i,0,n){ 210 if(v[i].fi>bonder+eps) break; 211 ans[cnt1++]=v[i].second; 212 } 213 sort(ans,ans+cnt1); 214 215 } 216 cout<<cnt1<<endl; 217 cout<<ans[0]; 218 rep(i,1,cnt1){ 219 cout<<" "<<ans[i]; 220 } 221 cout<<endl; 222 } 223 224 } 225 }