Probability Through Experiments

题目大意:

给定一个圆和圆上的一些点,输出这些点组成的锐角三角形的个数。

解题思路:

 

如果圆上的三个点能组成锐角三角形,那么圆心必在三角形内部,如果圆心在三角形的外部,那么该三角形必为钝角三角形,如果圆心在三角形的边上,那么该三角形必为直角三角形。所以对于圆上的每一个点,作过圆心和该点的一条直线,那么在直线左右两边的点和该点组成的三角形必为钝角三角形或者直角三角形(当圆上有另一个点在直线上),设总数为sum.

注意:上面方法计算到的三角形都被计算了两次!

输出结果为n*(n-1)*(n-2)-sum/2;

代码:

#include<stdio.h>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
#define eps 1e-6
using namespace std;
double angle[20005];
int n,r;
int bs(double a[], int l, int h, double v){   //大于等于v的下标(角度小于等于v的点的个数),
    int m;
    while ( l < h ){
        m = ( l + h ) >> 1;
        if (a[m] - v < eps) l=m+1;
        else h=m;
    }
    return l;
}
int serch(double a[],int l, int h,double v){   //角度为v的点是否在该圆上
    int m;
    while ( l < h ){
        m = ( l + h ) >> 1;
        if (abs(a[m]-v)<=eps) return m;
        if(a[m]<v+eps) l=m+1;
        else h=m;
    }
    return -1;
}
int main(){
    int left,right;
    int th=1;
    while(true){
        scanf("%d%d",&n,&r);
        if(n==0 && r==0) break;
        for(int i=0; i<n; i++){
            scanf("%lf",&angle[i]);
        }
        sort(angle,angle+n);
        LL sum=0;
        int tmp1,tmp2;
        double ang1,ang2;
        for(int i=0; i<n; i++){
            ang1=angle[i];     //ang1是该点的角度
            ang2=ang1-180.00;  //ang2是该点对于圆心对称的点的角度
            if(ang2<0) ang2+=360.00;
            tmp2=bs(angle,0,n,ang2);    //圆上角度小于等于v的点的个数
            if(tmp2>i){                 //i是角度小于该点的点的个数
                left=tmp2-i-1;
            }
            else{
                left=i-tmp2;
                if(serch(angle,0,n,ang2)!=-1){   //如果有点在该点的对面(关于圆心对称),进行特殊处理
                    left+=1;
                }
            }
            right=n-1-left;
            if(serch(angle,0,n,ang2)!=-1){
                right+=1;
            }
            sum+=(LL)(right*(right-1)/2+(left)*(left-1)/2);  //left是直径左边点的个数,
        }                                                    //right是直径右边点的个数
        LL nn=(LL)n;   //类型转换,否则下面运算会溢出,这儿卡了几次。
        LL all=nn*(nn-1)*(nn-2)/6;
        printf("Case %d: ",th++);
        printf("%lld\n",all-sum/2);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值