圆与三角形的几何+二分

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4153

题目大意:

第一行给出两个数字,n,r(这个圆的半径,感觉这个条件可有可无啊,反正我是没用上)

下面n行给出点的位置(是角度制的),这些点都是位于圆心是坐标原点的圆上。

任取三个点可以组合成ans个锐角三角形,要求出ans并输出。

解题思路:

还是老样子.....没思路.....自己脑子里想的就是暴力,但是肯定会超时,所以没敢动手写下去了。后来请教同学,学习了一个很巧妙的方法。如下

锐角三角形的个数=所有的三角形--钝角三角形--直角三角形,那么现在就直接转换成为找钝角三角形和直角三角形。

几何规律:如果在圆上任取三点,构成一个直角三角形,那么圆形肯定位于三角形的斜边上;如果构成一个钝角三角形,那么圆形一定在该三角形之外;构成锐角三角形,圆心则在三角形内部。

先把所有的点排序,然后依次遍历每个点,例如目前遍历到了i点(该点的角度值为p[i]),则找出p[i]+180的点的位置,判断这两个点之间有多少个点(如果p[i]+180点的位置上刚好有一个点与之重合,那么这个点应该也应该被包括),如果有m个点,那么从这m个点中,任意选取两个点,那么这两个点与i点一定会构成一个钝角或者直角三角形。


虽然分析完之后感觉应该不会太难,但是我至少wa了30遍才过掉这个题.....

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<algorithm>
#include<iostream>
#define maxn 40000+20//这里要开大一点
#define eps 1e-6//记得要加上它,我在这里也贡献了一次wa
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
LL n,r;//这个题目记得要用LL
double p[maxn];
LL bs(int i)//查找出两个点之间有多少个点
{
    LL low=i;
    LL high=2*n-1;
    while(low<high)
    {
        LL mid=(low+high+1)>>1;
        if(p[mid]<=p[i]+180.0+eps)
        {
            low=mid;
        }
        else
        {
            high=mid-1;
        }
    }
    return low-i;
}
int main()
{
    LL Ans;
    int cnt=0;
    while(scanf("%lld%lld",&n,&r)&&n&&r)
    {
        Ans=n*(n-1)*(n-2)/6;//题目中给出的算法,求总的三角形的个数
        for(int i=1;i<=n;i++)
            scanf("%lf",&p[i]);
        sort(p+1,p+1+n);
        for(int i=1;i<=n;i++)//这个是一个很巧妙的处理方法,可以学习一下
            p[i+n]=p[i]+360.0;
        LL ans=0;
        for(int i=1;i<=n;i++)
        {
            LL s=bs(i);
            ans+=s*(s-1)/2;//求出这些点能够组成多少个钝角或者直角三角形
        }
        printf("Case %d: %lld\n",++cnt,Ans-ans);
    }
    return 0;
}



你可能感兴趣的:(圆与三角形的几何+二分)