首页 > 其他分享 >[题解]POJ3675 Telescope——求多边形与圆相交部分的面积

[题解]POJ3675 Telescope——求多边形与圆相交部分的面积

时间:2024-07-17 20:29:45浏览次数:8  
标签:AB return Telescope double OB OA POJ3675 vec 题解

POJ3675 Telescope

题意简述

多测。每次给定一个\(N\)边形(保证相邻输入的顶点在多边形上也是邻接的),再给定一个以\((0,0)\)为圆心,半径为\(r\)的圆。

请计算出多边形和圆相交部分的面积(保留\(2\)位小数)。

  • \(3\le N\le 50\)
  • \(0.1\le r\le 1000\)
  • \(-1000\le x_i,y_i\le 1000\)。

输入格式见原题面。

思路分析。

首先简化一下问题。我们先不考虑圆,从原点出发,对这个多边形进行三角剖分。

如图,依次连接各顶点,形成\(\vec{a},\vec{b},\vec{c},\vec{d},\vec{e},\vec{f},\vec{g}\)。接下来重复下面的操作:

  • 连接相邻的两个向量\(\vec{x},\vec{y}\)形成一个三角形,如果\(\vec{x}\)到\(\vec{y}\)是顺时针,面积增加该三角形面积,否则减小该三角形面积(如图,红色部分是减去的,蓝色部分是增加的)。

我们发现这种方法可以很容易地处理各种多边形。如果有凹陷,被加的次数和被减的次数一定相等,相当于被抵消了。

如果再加上圆呢?那就把计算“三角形的面积”改成“三角形在圆内的面积”不就好了嘛。


计算“一个端点包括原点的三角形,在圆内的面积”,我们呢想到分类讨论三角形与圆的位置关系。

怎样优雅而有条理的讨论呢?我们可以用向量运算+代数的方式解决。

对于一个由向量\(\vec{OA}=(x_1,y_1),\vec{OB}=(x_2,y_2)\)组成的三角形\(AOB\),我们设\(\vec{AP}=t\times \vec{AB}\)。这样我们就可以用\(t\)表示出直线\(AB\)上的任意一点的坐标了:

\[\begin{aligned} \vec{OP}&=\vec{OA}+\vec{AP}\\ &=\vec{OA}+t\times \vec{AB}\\ &=\vec{OA}+t\times (\vec{OB}-\vec{OA})\\ &=(1-t)\times\vec{OA}+t\times \vec{OB}\\ &=(1-t)\times (x_1,y_1)+t\times (x_2,y_2)\\ &=((1-t)x_1+tx_2,(1-t)y_1+ty_2) \end{aligned}\]

显然当\(t\in[0,1]\)时。\(P\)是在线段\(AB\)上的;\(t>1\)时在\(AB\)延长线上,\(t<0\)时在\(AB\)反向延长线上。

由此我们想到,如果求出让\(P\)落在圆上的\(t\),就可以用此时\(P\)和\(A,B\)的位置关系进行讨论了。

所以可以列一个关于\(t\)的一元二次方程:

\[\begin{aligned} x_P^2+y_P^2-r^2&=0\\ ((1-t)x_1+tx_2)^2+((1-t)y_1+ty_2)^2-r^2&=0\\ \end{aligned}\]

化简并整理可得:

\[\begin{aligned} &(x_1^2+x_2^2-2x_1x_2+y_1^2+y_2^2-2y_1y_2)t^2\\ &+(2x_1x_2+2y_1y_2-2x_1^2-2y_1^2)t\\ &+(x_1^2+y_1^2-r^2)=0 \end{aligned}\\\]

解这个方程。

然后根据根的情况分类:

  • 无解:直线\(AB\)与圆无交点。答案就是图中扇形的面积。
  • 有\(2\)个相同的解:直线\(AB\)与圆相切。答案仍然是图中扇形的面积。
  • 有\(2\)个不同的解:设\(t_1,t_2\)分别表示较小和较大的解,进一步分类讨论:
    • \(\textbf{Case 1,2:}\quad t_1>1,t_2>1\)或\(t_1<0,t_2<0\):
      这两种情况可以放在一起考虑,都是\(P_1,P_2\)在线段\(AB\)外且同侧,即\(A,B\)在圆外且同侧,此时面积仍然是扇形。另一种情况的图就不放了。
    • \(\textbf{Case 3:}\quad t_1\in [0,1],t_2>1\)
      这种情况表示\(A\)在圆外\(B\)在圆内,即\(P_1\)在线段\(AB\)上而\(P_2\)不在。此时的面积是一个扇形+一个三角形。
    • \(\textbf{Case 4:}\quad t_1<0,t_2\in [0,1]\)
      和上面反过来,\(A\)在圆内,\(B\)在圆外,即\(P_2\)在线段\(AB\)上而\(P_1\)不在,同样是一个扇形+一个三角形。
    • \(\textbf{Case 5:}\quad t_1<0,t_2>1\)
      这说明\(A,B\)都在圆内部,即\(P_1,P_2\)都在线段\(AB\)外且不同侧,此时答案就是\(AOB\)的面积。
    • \(\textbf{Case 6:}\quad t_1\in[0,1],t_2\in[0,1]\)
      说明\(A,B\)都在圆外部且不同侧,即\(P_1,P_2\)都在线段\(AB\)上,此时答案是\(2\)个扇形+\(1\)个三角形。

就酱。

计算两向量面积需要用叉积,看到有些题解用海伦公式计算。但海伦公式更适用于已知三边长度,这种只给出两个向量的情况,还需要用勾股定理计算三边,再套公式求解。代码相较叉积求面积较为冗长,且要多次求平方&开根,所以速度和精度都有所丢失。因此计算向量形成的面积还是推荐用叉积。

计算两向量夹角、计算两向量叉积、计算端点包含原点的三角形在园内的面积,都需要用两个向量作为参数提供。所以需要斟酌一下答案的正负性。一般都和叉积统一,即:如果\(\vec{a}\)在\(\vec{b}\)的顺时针是正数,逆时针则是负数。这样统一之后就不容易混淆了。别忘了计算后求一下绝对值,因为节点遍历顺序的正反决定结果的正负。

还有,保留\(2\)位小数别忘了。

Code

注:POJ编译器较老,代码需要经过一番修改才能通过编译,这里就不放修改前的代码了。

点击查看代码

``#include<bits/stdc++.h>

define Pi 3.1415926535897932384626

using namespace std;
struct vec{
double x,y;
vec operator+ (const vec &b){return {x+b.x,y+b.y};}
vec operator- (const vec &b){return {x-b.x,y-b.y};}
vec operator* (const double t){return {xt,yt};}
}fir,pre,cur;
double cross(vec a,vec b){return a.xb.y-b.xa.y;}
double R,ans;
int n;
double angle(vec a,vec b){//a相对b的角度([-pi,pi])
double theta=atan2(a.x,a.y)-atan2(b.x,b.y);
if(theta>Pi) theta-=2Pi;
if(theta<-Pi) theta+=2
Pi;
return theta;
}//a在b的顺时针>0,逆时针<0,pi/-pi是反向,=0是同向
//扇形面积↓
double S_sect(double theta,double r){return thetarr/2;}
double S_tri_circ(vec OA,vec OB,double r){
double a=OA.xOA.x+OB.xOB.x-2OA.xOB.x+OA.yOA.y+OB.yOB.y-2OA.yOB.y;
double b=2OA.xOB.x+2OA.yOB.y-2OA.xOA.x-2OA.yOA.y;
double c=OA.xOA.x+OA.yOA.y-rr;
double delta=b
b-4ac;
if(delta<=0) return S_sect(angle(OA,OB),r);
double t1=(-b-sqrt(delta))/2/a,t2=(-b+sqrt(delta))/2/a;//解方程得到t
if((t1<0&&t2<0)||(t1>1&&t2>1)) return S_sect(angle(OA,OB),r);//Case 1,2
if(t2>1&&t1>=0&&t1<=1){//Case 3
vec OP1=OA+(OB-OA)t1;
return cross(OP1,OB)/2+S_sect(angle(OA,OP1),r);
}
if(t1<0&&t2>=0&&t2<=1){//Case 4
vec OP2=OA+(OB-OA)
t2;
return cross(OA,OP2)/2+S_sect(angle(OP2,OB),r);
}
if(t1<0&&t2>1) return cross(OA,OB)/2;//Case 5
vec OP1=OA+(OB-OA)t1,OP2=OA+(OB-OA)t2;//Case 6
return S_sect(angle(OA,OP1),r)+S_sect(angle(OP2,OB),r)+cross(OP1,OP2)/2;
}
int main(){
while(cin>>R>>n){
ans=0;
cin>>fir.x>>fir.y;
pre=fir;
while(--n){
cin>>cur.x>>cur.y;
ans+=S_tri_circ(pre,cur,R);
pre=cur;
}
ans+=S_tri_circ(cur,fir,R);
cout<<fixed<<setprecision(2)<<fabs(ans)<<"\n";
}
return 0;
}`

</details>

标签:AB,return,Telescope,double,OB,OA,POJ3675,vec,题解
From: https://www.cnblogs.com/Sinktank/p/18307540

相关文章

  • ABC361-D题解
    背景保佑LC能来一中。题意给你一个长度为\(n\)的初始字符串和目标字符串,都由W和B两种字符构成。现在初始字符串末尾接有两个空格字符,每次你可以在该字符串中选出连续两个非空格字符,并把它们按顺序与两个空格交换位置。问最少需要几步能得到目标字符串。分析首先如果两......
  • ABC361-C题解
    背景昨天打比赛的时候查了中考分,心快停跳了。题意从\(n\)个数字中删除\(k\)个数字,问剩下的数字中极差的最小值。分析首先把这\(n\)个数字排序,然后问题就可以转化为求这\(n\)个数字中所有长度为\(n-k\)的连续子段的极差的最小值。采用尺取法,可以从\(1\)开始枚举......
  • 题解:AT_abc360_c [ABC360C] Move It
    背景机房大佬掉大分了,乐悲。题意给你几个箱子和每个箱子里装有的东西\(a\)和对应的重量\(w\),现在要让每个箱子里都装有一个东西,每次可以移动任意一个箱子中的任意一个东西,代价为它的重量,问最小代价。分析贪心。首先最终状态里所有箱子一定只有一个东西,那么对于所有装东西......
  • 题解:P10723 [GESP202406 七级] 黑白翻转
    背景汗流浃背了。分析容易想到一个显然的思路:以任意节点为根,开始遍历。如果一个节点的子树里面有黑点,那么它必须保留,否则如果它是白点,则可以删去。但这个方法很容易举出反例:在这颗树中,如果以最上面的白点为根,那么手推发现算法显然错误。尝试进行修改,容易发现,对于类似的情况......
  • 题解:P10722 [GESP202406 六级] 二叉树
    题意一颗\(n\)节点的二叉树,每个节点非黑即白,给你\(Q\)次操作,每次给你一个\(u\),把\(u\)的子树内所有节点颜色反转,问最终每个节点的颜色。分析看到数据范围,首先把操作离线。容易发现如果一个节点重复操作奇数次,等效于操作一次,如果重复操作偶数次,等效于没操作。所以我们可......
  • 题解:B3646 数列前缀和 3
    分析板子题,线段树维护矩阵区间积,除了难写没什么思维难度。所以直接放代码吧。Code#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;inlineintread(){ intx=0,f=1;charch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getcha......
  • Masked Popcount 题解
    背景罚了一发,太菜了。为什么我终于有时间的时候她要考试?题意给你\(n,m\),问\(\sum_{i=0}^{n}popcount(i\&m)\)。其中\(\&\)代表位运算,\(popcount\)代表一个数字二进制下\(1\)的个数。分析两个数字在二进制下根据数据范围有\(60\)位。所以我们考虑每一位对答案的贡......
  • 题解:AT_abc359_c [ABC359C] Tile Distance 2
    背景去中考了,比赛没打,来补一下题。分析这道题让我想起了这道题(连题目名称都是连着的),不过显然要简单一些。这道题显然要推一些式子。我们发现,和上面提到的那道题目一样,沿着对角线走台阶,纵坐标走到以后再走横坐标显然是最优策略。这时候的答案就是横纵坐标差的和的一半(这就不用......
  • 题解:AT_abc357_f [ABC357F] Two Sequence Queries
    题意维护一个数据结构,支持两个数列的区间求和,和查询区间内两数列各元素积的和。分析线段树万岁!这道题要维护两个序列,所以线段树中要同时存储两个区间和。但还要在维护一个信息,是该区间内两序列元素积的和。大概长这样:structno{ intl,r; intda,db,ab; intta,tb;}t[m......
  • ABC357-C题解
    最近一直掉分,谔谔。分析发现机房里面除了我以外都用递归写的,那我就来讲一种非递归的吧。考虑第\(i\)级地毯拆成九块以后其实就是八块第\(i-1\)级地毯与一块大小为\(3^{i-1}\times3^{i-1}\)大小的白色地毯。所以用一个三维数组记录每一级地毯的状态,然后循环往上跑,每一级......