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

news/2024/11/13 10:04:28/文章来源:https://www.cnblogs.com/Sinktank/p/18307540

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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/745420.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【专题】2023中国机器人产业分析报告PDF合集分享(附原数据表)

原文链接:https://tecdat.cn/?p=34144 原文出处:拓端数据部落公众号 仿生机器人作为一类结合了仿生学原理的机器人,具备自主决策和规划行动的能力,正逐渐进入大众视野。它们的核心技术要素包括感知与认知技术、运动与控制技术、人机交互技术和自主决策技术。 阅读原文,获…

Splay 学习笔记

Splay 树, 或 伸展树,是一种平衡二叉查找树,它通过 Splay/伸展操作 不断将某个节点旋转到根节点,使得整棵树仍然满足二叉查找树的性质,能够在均摊 O(\log N) 时间内完成插入,查找和删除操作,并且保持平衡而不至于退化为链。 Splay 树由 Daniel Sleator 和 Robert Tarjan …

redis学习-12(实现分布式锁、消息队列、缓存一致性问题、单线程快的原因、跳跃表)

引用以下内容: redis实现分布式锁:Redis分布式锁-这一篇全了解(Redission实现分布式锁完美方案) Redis实现分布式锁的7种方案,及正确使用姿势! redis实现消息队列Redis 的学习教程(十)之使用 Redis 实现消息队列 缓存一致性问题 想要保证数据库和 Redis 缓存一致性,推荐…

数据的运算(上)

逻辑门电路多路选择器和三态门加法器 一位全加器并行进位加法器

idea开发工具配置git,连接到gitee远程仓库

1. 打开idea,Settings里找到如下位置,正常idea会自动找到git,test测试,显示版本号说明正常 2. 创建本地Git仓库,默认就是当前项目路径, 不要修改,直接创建 3. 创建后自动识别出待提交的文件,输入说明,提交,提交后让输入git名称和邮箱,设置并提交,提交成功。我这个项…

使用Apache POI 处理Miscrosoft Office各种格式文件

介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。一般情况下,POI 都是用于操作 Excel 文件。Apache POI 的应用场景: ● 银行网银系统导出交易明细 ● 各种业务…

闲话 717 - LGV 引理的小应用

717这是我们的某一天的联考题目:\(n\le 500\)。 显然使用平面图完美匹配计数可以获得 \(O(n^6)\),但是有一种神秘的对路径的双射。当时我们都认为这是超级人类智慧,但是今天看书发现是书上的某个例的题的方法(有不同)。。 考虑对正六边形的菱形密铺方案数(上图)。可以等…

useHeadSafe:安全生成HTML头部元素

title: useHeadSafe:安全生成HTML头部元素 date: 2024/7/17 updated: 2024/7/17 author: cmdragon excerpt: 摘要:“useHeadSafe”是Vue.js组合函数,用于安全生成HTML头部元素,通过限制输入值格式避免XSS等安全风险,提供了安全值白名单确保只有安全属性被添加。 categor…

Goby漏洞发布 | CVE-2024-4879 ServiceNowUI /login.do Jelly模板注入漏洞【已复现】

漏洞名称:ServiceNowUI /login.do Jelly模板注入漏洞(CVE-2024-4879) English Name:ServiceNowUI /login.do Input Validation Vulnerability(CVE-2024-4879) CVSS core: 9.3 漏洞描述: ServiceNow 是一个业务转型平台。通过平台上的各个模块,ServiceNow 可用于从人力资…

EMQX配置用户名和密码开启emqx_auth_mnesia认证方式连接

1、 找到MQtt 的 /etc/plugins/ 文件夹下的emqx_auth_mnesia.conf 文件 vim打开编辑该文件,根据例子添加账号密码 并保存 添加内容: auth.user.1.username = admin auth.user.1.password = 123456 2、配置禁止匿名登录(安全认证) 找到emqx.conf编辑## Allow anonymous authe…

NETCORE -MinIO的基本使用

NETCORE -MinIO的基本使用环境:.net6 + minio minio服务部署:https://www.cnblogs.com/1285026182YUAN/p/18308075一. 创建 net6项目 二. 安装minio nuget包 三.在appsetting.json 配置文件中设置MinIO配置 {"Logging": {"LogLevel": {"Default&q…

gwang.top:一键官网查询

gwang.top是由小章做的一款在线工具,专注于帮助用户快速查找软件、机构或公司的官方网站,本文介绍这款工具的使用。原文地址:https://itxiaozhang.com/one-click-official-site-query/ 本文配合视频食用效果最佳,视频教程在文章末尾。简介 gwang.top 是一个小章做的在线查询…