UVA11186题解

题意简述

建立一个极坐标系,在一个圆心在极点,半径为 $r$ 的圆周上有 $n$ 个点,求这些点围成的所有三角形面积之和,对于每个点给出一个 $\theta$,代表这个点的极坐标为 $(r,\theta)$。

题目分析

其他题解中的算法时间复杂度为 $O(n^3)$,对于题目中 $n \leq 500$ 的数据范围足够了,但数据稍有加强就会被卡,在此给出一种时间复杂度为 $O(n^2)$ 的算法。

首先我们分析一下圆周上三个点组成的三角形面积该如何求。如图所示,圆内接三角形的面积都可以由圆的面积减去三个弓形(绿色部分)的面积之和来求出。 解释 那么,所有三角形面积之和就是 $C_n^3 \times S_{\odot O}$ 减去每个三角形所对应的三个弓形面积之和。接下来,我们可以将给出的 $\theta$ 递增排序,那么对于两个点 $i$、$j$(假设 $i<j$),在其之间有 $j-i-1$ 个点,如图所示,弦 $ij$ 两侧的弓形在所有三角形对应的弓形中分别共被减去 $j-i-1$ 次与 $n+i-j-1$ 次。 解释2 那么,对于每个弓形被减的次数已经知道了,只需要再计算出每个弓形的面积即可。对于两个点 $i$ 与 $j$,以 $ij$ 为弦的扇形(指对应圆心角较小的弓形)面积即为$S = \frac{(\theta _j-\theta_i)\times \pi \times r^2 }{360 \degree} -\frac{r^2 \times \sin(\theta _j-\theta_i)}{2} $,而另一侧面积较大的弓形面积为 $\pi \times r^2 -S$。另外,需要注意的一点是计算三角函数时为了适应 C++ 的标准,应将输入的角度转换为弧度形式存储,并且这样可以简化最终的答案。

最后给出代码:

#include<bits/stdc++.h>
using namespace std;
const double Pi=2*acos(0);//计算圆周率。 
int n,r;
double A[510],ans,th,s;
int main() 
{
    while(scanf("%d%d",&n,&r)&& n&&r) 
    {
        //为了方便,我将面积在最后才乘的 r*r。 
        ans=Pi*(n*(n-1)*(n-2)/6); 
        for(int i=1;i<=n;i++)
            scanf("%lf",&A[i]),A[i]=A[i]*Pi/180.0;//转成弧度。 
        sort(A+1,A+n+1);//角度排序。 
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++) 
            {
                th=(A[j]-A[i])/2,s=th-cos(th)*sin(th);//th 为圆心角,s为小弓形面积(没乘 r*r)。 
                ans-=(j-i-1)*(Pi-s)+(n-j+i-1)*s;//减去弓形面积。 
            }
        ans*=r*r;
        printf("%.0lf\n",ans);
    }
    return 0;
}
posted @ 2021-08-28 17:32  Hadtsti  阅读(1)  评论(0编辑  收藏  举报  来源