news 2026/7/9 7:56:53

UVa 634 Polygon

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVa 634 Polygon

题目描述

给定一个简单多边形(边与坐标轴平行,但算法适用于任意简单多边形)及其顶点坐标(按顺序给出,可能是顺时针或逆时针),以及一个待检测的点PPP。要求判断点PPP是否位于多边形内部(包括边界)。输入包含多组数据,每组以顶点个数nnn开始,随后nnn行顶点坐标,最后一行给出点PPP的坐标。输入以n=0n = 0n=0结束。

输出时,若点在多边形内部(含边界),输出T,否则输出F

输入格式

每组数据第一行为一个整数nnnn≤1000n \le 1000n1000),表示多边形顶点个数。接下来nnn行,每行两个整数xxxyyy,按顺序给出多边形顶点坐标。随后一行包含两个整数,为待检测点PPP的坐标。输入以n=0n = 0n=0结束。

输出格式

对于每个点,输出一行字符:T表示点在多边形内部(或边界),F表示点在多边形外部。

样例

输入

4 1 1 1 3 3 3 1 2 2 2 12 1 1 1 9 3 9 3 5 5 5 5 9 7 9 7 1 5 1 5 3 3 3 1 4 2 0

输出

T F

题目分析

本题是经典的点与多边形位置关系判定问题。常用的算法是射线法(奇偶规则):从点PPP向右作水平射线,统计该射线与多边形边的交点数。若交点数为奇数,则点在多边形内部;若为偶数,则在外部。若点恰好在边上,也应判定为内部。

在实现时,需要处理射线与多边形顶点相交的边界情况,以避免重复计数。通常的解决方案是:只统计那些跨越射线水平线且两个端点位于射线水平线两侧(或者其中一个端点在射线上,另一个端点在上方)的边。代码中采用了一种简洁的处理方式:对每条边,先判断射线与边所在线段是否相交(通过方向叉积),然后对顶点相交的情况,只计数那些边的两个端点都在射线水平线上方(即side.start.y >= ray.start.y && side.end.y >= ray.start.y)的情况,从而确保每个顶点只被计数一次。

解题思路

射线法基本原理

从点PPP向右作一条水平射线,与多边形的边求交。若射线穿过多边形边界奇数次,则PPP在多边形内部;否则在外部。

交点判断

对于每条边ABABAB和射线(起点为PPP,方向向右),判断它们是否相交:

  1. 若射线与边无交点,则跳过。
  2. 若射线与边相交于边内部(非端点),则计数加一。
  3. 若射线与边的某个端点相交,则必须统一规则,防止端点被重复计数。代码中采用“只计数边的两个端点都在射线水平线上方”的规则,即只有当边的两个端点的yyy坐标都不小于射线起点的yyy坐标时,才认为该交点有效。

实际上,更常见的做法是:若射线与边的交点恰好是边的上端点,则计数,下端点则不计数。代码中的规则与之等价。

具体步骤

  1. 读入多边形顶点数组。
  2. 构造一条水平射线,起点为点PPP,终点为xxx坐标足够大的点(例如2×2 \times2×多边形最右顶点的xxx坐标,确保射线能穿过多边形)。
  3. 遍历多边形的每条边,调用segmentsIntersect判断射线与边是否相交。
  4. 统计相交次数,若为奇数则返回true,否则false

边界处理

  • 点恰好在边上的情况:由于题目输入满足一定条件(点PPP的坐标均为偶数,多边形边长为偶数等),但算法中未特殊处理,在判断相交时,若点与边共线且点在边上,则方向叉积为000,且点位于边范围内,此时应判定为内部。但代码中对于共线情况直接返回false,这可能漏掉点在边上的情况。然而根据题目输入的特殊性(点PPP坐标为偶数,多边形边长为偶数,且至少一个顶点坐标为奇数),点PPP不可能落在多边形边上(因为边上的点至少有一个坐标为奇数?或者边长偶数导致边界点坐标奇偶性固定),因此可以安全忽略边界情况。为通用性,也可增加点在边上的显式判断,但代码未做,故保持原样。

复杂度分析

  • 每组数据,对每条边进行常数次叉积运算,时间复杂度O(n)O(n)O(n),其中nnn为顶点数(n≤1000n \le 1000n1000)。
  • 空间复杂度O(n)O(n)O(n),用于存储顶点。

代码实现

// Polygon// UVa ID: 634// Verdict: Accepted// Submission Date: 2016-08-29// UVa Run Time: 0.000s//// 版权所有(C)2016,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;constintMAX_VERTICES=1100;constintEPSILON=0;structpoint{doublex,y;};structsegment{point start,end;};structpolygon{intvertexNumber;point vertex[MAX_VERTICES];};// 使用叉积来表示线段的相对方向。doubledirection(point a,point b,point c){return(b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);}// 判断多边形的边是否在射线上方。boolisSideAboveRay(segment ray,segment side){returnside.start.y>=ray.start.y&&side.end.y>=ray.start.y;}// 根据设定的交点数规则判断射线与多边形的边是否相交。boolsegmentsIntersect(segment ray,segment side){doubled1,d2,d3,d4;d1=direction(ray.start,ray.end,side.start);d2=direction(ray.start,ray.end,side.end);d3=direction(side.start,side.end,ray.start);d4=direction(side.start,side.end,ray.end);// 跨越式相交。if((d1*d2<0)&&(d3*d4<0))returntrue;// 不相交。if((d1*d2>0)||(d3*d4>0))returnfalse;// 共线,不论线段是否重合,均规定为不相交。if((fabs(d1)<=EPSILON&&fabs(d2)<=EPSILON)||(fabs(d3)<=EPSILON&&fabs(d4)<=EPSILON))returnfalse;// 相交于顶点,判断是否在射线上方。if(fabs(d1)<=EPSILON||fabs(d2)<=EPSILON||fabs(d3)<=EPSILON||fabs(d4)<=EPSILON)returnisSideAboveRay(ray,side);returnfalse;}boolisPointInPolygon(point&p,polygon&pg){// 找到多边形顶点中位于最右边的点的横坐标。doublerightX=pg.vertex[0].x;for(inti=0;i<pg.vertexNumber;i++)if(pg.vertex[i].x>rightX)rightX=pg.vertex[i].x;intnumberOfIntersection=0;segment ray=(segment){p,(point){2*rightX,p.y}};for(inti=0;i<pg.vertexNumber;i++){segment side=(segment){pg.vertex[i],pg.vertex[(i+1)%pg.vertexNumber]};if(segmentsIntersect(ray,side))numberOfIntersection++;}// 测试交点个数奇偶性。return((numberOfIntersection&1)==1);}intmain(){cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);point p;polygon pg;while(cin>>pg.vertexNumber,pg.vertexNumber){for(inti=0;i<pg.vertexNumber;i++)cin>>pg.vertex[i].x>>pg.vertex[i].y;cin>>p.x>>p.y;cout<<(isPointInPolygon(p,pg)?'T':'F')<<'\n';}return0;}

总结

本题使用射线法判断点与多边形的位置关系,通过方向叉积判断线段相交,并采用“端点只计上方”的规则避免顶点重复计数。由于输入数据满足特定奇偶性条件,边界情况被简化,使得算法可以稳定运行。时间复杂度为O(n)O(n)O(n),空间复杂度O(n)O(n)O(n),适合n≤1000n \le 1000n1000的数据规模。此解法是计算几何中点与多边形关系判定问题的经典实现,掌握该方法对解决类似几何问题很有帮助。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/9 7:56:51

资源血缘不是可选项:规模化BI推广中变更管理的关键抓手

导语 在给一家零售集团做BI选型评估时&#xff0c;有一个很典型的问题&#xff1a;资源血缘这个功能&#xff0c;是不是"看起来很酷但用得不多"&#xff1f;——潜台词是&#xff0c;能不能砍掉、能不能延后上、能不能只给管理员看看拓扑图就行。这个问题背后&#x…

作者头像 李华
网站建设 2026/7/9 7:56:13

docker安装禅道

1. docker compose文件 services:# 数据库服务zentao-db:image: mariadb:10.6.18container_name: zentao-dbports:- 3306:3306volumes:# 数据持久化&#xff1a;挂载到宿主机,前半段为自己本机地址- /data/app/mysql/data:/var/lib/mysql# 挂载自定义配置文件目录,提前准备后配…

作者头像 李华
网站建设 2026/7/9 7:56:04

CART vs ID3 vs C4.5:3种决策树算法在金融风控场景下的性能对比

CART vs ID3 vs C4.5&#xff1a;金融风控场景下的决策树算法深度评测1. 决策树算法在金融风控中的核心价值金融风控领域对算法的要求近乎苛刻——需要模型同时具备高准确性、强解释性和实时响应能力。这正是决策树算法在信贷审批、反欺诈等场景中占据主导地位的根本原因。不同…

作者头像 李华
网站建设 2026/7/9 7:55:51

Windows安卓应用安装终极指南:APK安装器完全手册

Windows安卓应用安装终极指南&#xff1a;APK安装器完全手册 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 告别笨重模拟器&#xff0c;在Windows电脑上直接运行安卓应…

作者头像 李华
网站建设 2026/7/9 7:54:00

从 13.6 万星到 25+ 平台,Skills 正在成为标准

OK&#xff0c;到此为止我们只聊了「Skills 是什么」和「怎么写」。但真正让我觉得这个话题值得专门写一篇文章的&#xff0c;是它的生态——这场爆发来势之快超出了大多数人的预期。数据层面截至 2026 年 5 月&#xff1a;项目Stars定位anthropics/skills136,000Skills 官方仓…

作者头像 李华
网站建设 2026/7/9 7:53:36

鸿蒙新特性:Radio 单项选择组件——构建健康评估问卷

单选是表单中最基础的交互。性别选择、支付方式、评分档位、问卷答案——所有这些"多选一"的场景都需要单选按钮。Radio 组件通过互斥的圆形按钮和清晰的选中标记&#xff0c;让用户在多个互斥选项中做出明确的单一选择。 HarmonyOS NEXT ArkUI 提供了 Radio 组件——…

作者头像 李华