题解:UVA11186 正多边形 Circum Triangle

题意简述

给你一个圆的半径 rr 和圆上的 nn 个点,然后任意选择三个点,会组成一个三角形。要输出所有符合要求的三角形面积之和。

思路

注意到是在圆上,因此任选三个点一定能组成三角形。

因为 n500n\le 500,所以考虑暴力枚举。

首先需要将极坐标转化为平面直角坐标,设极坐标下圆半径为 rr,给定的角为 α\alpha,平面直角坐标下横坐标为 xx,纵坐标为 yy。则:

  • x=rcosαx=r\cos\alpha
  • y=rsinαy=r\sin\alpha

这个其实蛮好证明的:

根据三角函数的定义,可得 cosα=xr\cos\alpha=\dfrac{x}{r}sinα=yr\sin\alpha=\dfrac{y}{r} 两个式子。

移项即可得到上面的式子。

现在的问题在于如何快速计算任意三角形面积。

我们可以采用下面的方法:

  1. S=12ahS_{\triangle}=\dfrac{1}{2}ah

优点:只有乘法。

缺点:aahh 难求。

  1. S=12absinCS_{\triangle}=\dfrac{1}{2}ab\sin C

缺点:sinC\sin C 难求。

  1. S=p(pa)(pb)(pc)S_{\triangle}=\sqrt{p(p-a)(p-b)(p-c)},其中 p=a+b+c2p=\dfrac{a+b+c}{2}

优点:三边使用两点距离公式 dis=(x1x2)2+(y1y2)2dis=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2} 即可求。

缺点:因为要多次根号,所以常数特大,在 n500n\le 500 时过不去。

  1. 向量叉积法

向量积可以被定义为:

模长:a×b=a×bsinα|\bold{a}\times \bold{b}|=|\bold{a}|\times |\bold{b}| \sin \alpha(在这里 α\alpha 表示两向量之间的夹角(共起点的前提下),它位于这两个矢量所定义的平面上,0απ0\le \alpha\le \pi。)

方向:a\bold{a}b\bold{b} 的向量积的方向与这两个向量所在平面垂直,且遵守右手定则。(一个简单的确定满足“右手定则”的结果向量的方向的方法是这样的:若坐标系是满足右手定则的,当右手的四指从 a\bold{a} 以不超过180度的转角转向 b\bold{b} 时,竖起的大拇指指向是 c\bold{c} 的方向。)(以上文段摘自百度百科)

观察法 22 的公式,不难注意到上面叉积的模长就是三角形面积的两倍。

但是我们如何快速求出叉积的模长呢?

下面是向量叉积的行列式定义(三维空间):

a=(u1,u2,u3)\bold{a}=(u_1,u_2,u_3)b=(v1,v2,v3)\bold{b}=(v_1,v_2,v_3),则

a×b=ijku1u2u3v1v2v3\bold{a}\times \bold{b}=\left | \begin{matrix}\bold{i} &\bold{j} & \bold{k} \\u_1 &u_2 &u_3 \\v_1 &v_2 &v_3 \\\end{matrix} \right |

不难发现,因为这张图是二维空间,所以 u3u_3v3v_3 都是 00

三个向量 i,j,k\bold{i},\bold{j},\bold{k} 都是单位向量。

把它用行列式展开,得:

a×b=u2u3v2v3i+u1u3v1v3j+u1u2v1v2k=(u2v3u3v2)i+(u1v3u3v1)j+(u1v2u2v1)k\begin{align}\bold{a}\times \bold{b }&=\left | \begin{matrix}u_2 &u_3 \\v_2 &v_3 \\\end{matrix} \right | i+\left | \begin{matrix}u_1 &u_3 \\v_1 &v_3 \\\end{matrix} \right | j+\left | \begin{matrix}u_1 &u_2 \\v_1 &v_2\\\end{matrix} \right | k \nonumber\\&=(u_2v_3-u_3v_2)i+(u_1v_3-u_3v_1)j+(u_1v_2-u_2v_1)k\end{align}

显然 u3u_3v3v_300,所以前两项就不用管了。

k\bold{k} 是单位向量,所以它的模长是 11

所以 u×v=(u1v2u2v1)|\bold{u}\times \bold{v}|=(u_1v_2-u_2v_1)

这样我们就能快速求了。

代码

#include<bits/stdc++.h>
using namespace std;
const double pi=acos(-1);
int n;
double r;
struct node{
	double x,y;
}a[505];
node operator -(node a,node b) {
	return (node){a.x-b.x,a.y-b.y};
}
const double eps=0.00000001;
//double X(double a,double b,double c,double d){
//	return a*d-b*c;
//}
//double S(node x,node y,node z){
//	return fabs(X(y.x-x.x,y.y-x.y,z.x-x.x,z.y-x.y));
//}
double Xx(node xx,node yy){
	return xx.x*yy.y-xx.y*yy.x;
}
double Sx(node xx,node yy,node zz){
	return fabs(Xx(yy-xx,zz-xx));
}
int main(){
	while(1){
		cin>>n>>r;
		if(n==0&&abs(r)<=eps)break;
		for(int i=1;i<=n;i++){
			double q;
			cin>>q;
			q=q*1.0/180*pi;
			a[i].x=cos(q)*r;
			a[i].y=sin(q)*r;
		}
		double ans=0;
		for(int i=1;i<=n;i++){
			for(int j=i+1;j<=n;j++){
				for(int k=j+1;k<=n;k++){
					ans+=Sx(a[i],a[j],a[k]);
				}
			}
		}
		printf("%.0lf\n",ans/2);
	}
	return 0;
}
posted @   Weslie_qwq  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示