[题解]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\)上的任意一点的坐标了:
\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\)的一元二次方程:
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}\]
化简并整理可得:
&(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\)个三角形。

- \(\textbf{Case 1,2:}\quad t_1>1,t_2>1\)或\(t_1<0,t_2<0\):
就酱。
计算两向量面积需要用叉积,看到有些题解用海伦公式计算。但海伦公式更适用于已知三边长度,这种只给出两个向量的情况,还需要用勾股定理计算三边,再套公式求解。代码相较叉积求面积较为冗长,且要多次求平方&开根,所以速度和精度都有所丢失。因此计算向量形成的面积还是推荐用叉积。
计算两向量夹角、计算两向量叉积、计算端点包含原点的三角形在圆内的面积,都需要用两个向量作为参数提供。所以需要斟酌一下答案的正负性。一般都和叉积统一,即:如果\(\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 {x*t,y*t};}
}fir,pre,cur;
double cross(vec a,vec b){return a.x*b.y-b.x*a.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-=2*Pi;
if(theta<-Pi) theta+=2*Pi;
return theta;
}//a在b的顺时针>0,逆时针<0,pi/-pi是反向,=0是同向
//扇形面积↓
double S_sect(double theta,double r){return theta*r*r/2;}
double S_tri_circ(vec OA,vec OB,double r){
double a=OA.x*OA.x+OB.x*OB.x-2*OA.x*OB.x+OA.y*OA.y+OB.y*OB.y-2*OA.y*OB.y;
double b=2*OA.x*OB.x+2*OA.y*OB.y-2*OA.x*OA.x-2*OA.y*OA.y;
double c=OA.x*OA.x+OA.y*OA.y-r*r;
double delta=b*b-4*a*c;
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;
}
[题解]POJ3675 Telescope——求多边形与圆相交部分的面积的更多相关文章
- 牛客网暑期ACM多校训练营(第三场)J 多边形与圆相交的面积
链接:https://www.nowcoder.com/acm/contest/141/J 题目描述 Eddy has graduated from college. Currently, he is ...
- poj3675 求多边形与圆的面积交
题意:给出多边形的顶点坐标.圆的圆心坐标和半径,求面积交 sol:又是模板题啦= = 注意poj的C++好像认不出hypot函数,要稍微改写一下. hypot(double x,double y):即 ...
- HDU 3467 (求五个圆相交面积) Song of the Siren
还没开始写题解我就已经内牛满面了,从晚饭搞到现在,WA得我都快哭了呢 题意: 在DotA中,你现在1V5,但是你的英雄有一个半径为r的眩晕技能,已知敌方五个英雄的坐标,问能否将该技能投放到一个合适的位 ...
- java求两个圆相交坐标
最近由于项目需要,根据两个圆函数求出相交的坐标.实现代码如下,另感谢两圆求交点算法实现Java代码,虽然他所贡献的代码中存在问题,但仍有借鉴意义. 1.两个圆相交的数学求法 在中学数学中我们知道,一个 ...
- hdu 4404 Worms(多边形与圆的交)
求出爆炸点的坐标,就成了多边形与圆相交面积的模板题了... #include<algorithm> #include<iostream> #include<cstring ...
- POJ 2546 Circular Area(两个圆相交的面积)
题目链接 题意 : 给你两个圆的半径和圆心,让你求两个圆相交的面积大小. 思路 : 分三种情况讨论 假设半径小的圆为c1,半径大的圆为c2. c1的半径r1,圆心坐标(x1,y1).c2的半径r2,圆 ...
- hdu5858 Hard problem(求两圆相交面积)
题目传送门 Hard problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Other ...
- hdu 5120(2014北京—求圆相交)
题意:求环的相交面积 思路: 通过画图可知,面积= 大圆相交面积 - 大小圆相交面积*2 + 小小圆相交面积 再通过圆相交模板计算即可 #include <iostream> #incl ...
- POJ 2546 & ZOJ 1597 Circular Area(求两圆相交的面积 模板)
题目链接: POJ:http://poj.org/problem? id=2546 ZOJ:problemId=597" target="_blank">http: ...
- 两圆相交求面积 hdu5120
转载 两圆相交分如下集中情况:相离.相切.相交.包含. 设两圆圆心分别是O1和O2,半径分别是r1和r2,设d为两圆心距离.又因为两圆有大有小,我们设较小的圆是O1. 相离相切的面积为零,代码如下: ...
随机推荐
- Spring中的单例Bean是线程安全的吗
前言 Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean ...
- Spring注解之@Autowired:Setter 方法上使用@Autowired注解
可以在 JavaBean中的 setter 方法中使用 @Autowired 注解.当 Spring遇到一个在 setter 方法中使用的 @Autowired 注解时,它会在方法中按照类型自动装配参 ...
- K8s新手系列之指定Pod调度到指定节点上
概述 在 Kubernetes 中,Pod的调度是通过kube-schedule来实现的,Pod的调度会经过一系列算法来进行完成. 在实际生产过程中,我们想让Pod调度到我们想要的节点上,往往通过ku ...
- java 钉钉群机器人发消息通知工具类
测测类 /** * 测试钉钉群通知 * * @return */ @GetMapping("/testDingTalk") public Result testDingTalk() ...
- 「Note」图论方向 - 图论基础
1. 差分约束 1.1. 简介 差分约束算法用于解决如下问题:给出若干形如 \(x_a-x_b\le c\) (均为整数,可以为负数)的不等式,求一组解 \(\{x_i\}\),若不存在解则判断无解. ...
- 函数使用十二:BAPI_CONTRACT_CREATE
*&---------------------------------------------------------------------* *& Report ZBAPI_WB2 ...
- AI大模型应用开发-用LangChain构建带Agen流程的RAG系统
随着大模型(LLM)能力越来越强,RAG(Retrieval Augmented Generation,检索增强生成)技术成为增强大模型知识准确性的关键手段. 通过检索实时数据.外部文档,模型能回答更 ...
- 五、kernel修改屏幕配置
2.3.修改屏幕配置 2.3.1.配置 gpio 修改 ./rk_linux_sdk/kernel/arch/arm64/boot/dts/rockchip/rk3566-evb2-lp4x-v10. ...
- C#如何取出非公共成员
https://blog.csdn.net/yueguangzhiyuan/article/details/8926131 一般而言,非公共成员是受保护的,不能被外部访问的,这些都是基于安全性考虑.可 ...
- webpack项目的全局变量
熟悉vue的同学,肯定知道有.env或env.development类似于这样的配置文件来定义app的全局变量.那么这是如何实现的呢?如果我没用vue,比如我用的react或者纯手工的webpack项 ...