57 圆与圆的面积交(2017年秦皇岛区域赛)

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.

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.

Sample Input

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

Sample Output

1
1
2
2 3

这道题目的意思是最初的时候有一个圆,半径是R,圆心是原点,这个圆中有很多点,一段时间后者个圆就会变成是一个半径是r的圆,并且这个后来的这个半径为r的圆一定全部都在半径为R的圆内部,让我们来输出最有可能在后来这个半径为r的圆内部的点是哪一个;

分析一下后来这个半径为r的圆心只可能在,距离原点的距离小于R-r的区域内部,否则的话这个圆就会有一部分在大圆的外部

,所以就会有两个圆一个是半径是R,另外一个是半径R-r,圆心是原点的圆,并且后者这一个圆是我们可以选择安全区域的圆心的

所有可能情况,那么现在的话问题可以转化一下就是我们以给定的点为圆心,以半径r画一个半径为r的圆,这个圆与圆心分布圆的面积交的大小就决定了,这一个点安全概率的大小,

所以这里出来了

1)一种解题目的思路就是圆面积交的大小关系;

2) 第二种思路就是我们可以观察,点与安全区域圆心所在圆的位置关心来确定我们安全概率的大小;

有三种情况:

1)如果以点为圆心,r为半斤的圆能够把,半径为R-r的那一个圆都给包括在内的话,这里的面就交就是R-r这一个圆的面积最大;

2)第二种就是如果能够能够包含这个点的安全区域的圆心全部是在以原点为圆心,R-r为半径的区域内的话,那么这样的话,我们画的那个以这个点为圆心,r为半径的圆全部是在以原点为圆心,R-r为半径的小圆的内部,那么这样的话,这一个点在安全区域的概率就是半径为r圆的面积;

 

3)第三种就是以这个点为圆心r为半径的圆与原点为圆心,R-r为半径的圆二者是相交的关系不存在,谁包含着谁的关系,这个时候我们要看的是这个点到原点距离的远近,越近概率越大;

这三种情况的点落在安全区域的概率是从大到小的;

#include <bits/stdc++.h>
using namespace std;
const int Max = 1e5+10;
#define eps 0.0000000001
struct node {
  int id;
  double dis;
}s1[Max],s2[Max],s3[Max];
double abs1 ( double a){
   if(a<0) a=-a;
   return a;
}
bool cmp(node a, node b){
   if(a.dis!=b.dis)
   return a.dis<b.dis;
   return a.id<b.id;
}
int num1,num2,num3;
int main(){
   int t;
   scanf("%d",&t);
   while(t--){
      double R,r;
      int n;
      scanf("%d %lf %lf",&n,&R,&r);
      num1=num2=num3=0;
      for(int i=1;i<=n;i++){
         double x,y;
         scanf("%lf %lf",&x,&y);
         double dis=sqrt(x*x+y*y);
         if(dis+R<=r*2){
            s3[num3++].id=i;
         }
         else if(abs1(dis+r*2)<=R){
           s1[num1++].id=i;
         }
         else {
           s2[num2].dis=dis;
           s2[num2++].id=i;
         }
      }
      if(num3!=0){
        printf("%d\n",num3);
        for(int i=0;i<num3;i++){
            printf("%d%c",s3[i].id,(i==num3-1)?'\n':' ');
        }
      }
      else if(num1!=0){
        printf("%d\n",num1);
        for(int i=0;i<num1;i++){
          printf("%d%c",s1[i].id,(i==num1-1)?'\n':' ');
        }
      }
      else {
        sort(s2,s2+num2,cmp);
        int num=0,i=0;
        if(num2>0){
          double ans=s2[0].dis;
        while(abs1(ans-s2[i].dis)<=eps&&i<num2){
             num++;
             i++;
        }
        }
        printf("%d\n",num);
        for(int j=0;j<i;j++){
          printf("%d%c",s2[j].id,(j==i-1)?'\n':' ' );
        }
      }
   }
   return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值