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 }
View Code

 

  

posted @ 2018-10-14 20:34  StarHai  阅读(375)  评论(0编辑  收藏  举报