POJ 3335 Rotating Scoreboard(半平面交求多边形核)
题意 : 给你一个多边形,问你在多边形内部是否存在这样的点,使得这个点能够看到任何在多边形边界上的点。
思路 : 半平面交求多边形内核。
关于求多边形内核的算法
什么是多边形的内核?
它是平面简单多边形的核是该多边形内部的一个点集,该点集中任意一点与多边形边界上一点的连线都处于这个多边形内部。就是一个在一个房子里面放一个摄像 头,能将所有的地方监视到的放摄像头的地点的集合即为多边形的核。

如上图,第一个图是有内核的,比如那个黑点,而第二个图就不存在内核了,无论点在哪里,总有地区是看不到的。
那么,如何求得这个内核区间呢?通常的算法是用两点的直线去不断切割多边形,切割到最后剩下的,就是内核区间了。
我们都知道一条直线可以将平面切割成两个区域,假设直线方程为
ax+by+c==0,那么,两个平面可分别表示成ax+by+c>=0 和 ax+by+c<0
具体如何用程序实现直线对多边形的切割呢?
流程是这样的:
1、 用一个顺时针或者逆时针的顺序,将最初的多边形的点集储存起来。
2、 按顺序取连续的两个点组成一条直线,用这条直线来切割原先的多边形
我首先假设点是顺时针储存的,如图:

此时,多边形的点集是{1,2,3,4,5,6,7,8,9,10}
取点1,和点2组成直线ax+by+c==0,这时候,将点集中的点一次带入方程ax+by+c,得到的值都将会是大于等于0的,说明所有的点都在该直线的同一侧,继续保持点集不变
取点2和点3组成直线,同样,将点集中的点依次带入方程ax+by+c中,此时,4和5两个点的结果是小于0的,而其他的点的值依旧是大于等于0,这时候说明4和5两个点被切割出了该多边形,于是现在点集只剩下{1,2,3,6,7,8,9,10,X},(X是直线23和直线56的交点)
依次类推,一直执行到点10和点1,那么内核的集合就得到了。
值得说明的是,这个例子的图形比较特殊,全是直角,如果图形比较随意,那么当某一个点被断定在多边形区间之外的时候,我们还应该考虑它和它相邻的两个点各自组成的直线和ax+by+c有没有交点,有交点的话,更新的点集中还应该加上这些交点,比如例子中执行完点2和点3组成的直线后,点集是{1,2,3,6,7,8,X},其中3和X就是这样的结果
还有,为什么将所有的点依次执行一遍,然后取剩下的某一边的点构成新的点集就够了呢?答案是,点是顺时针或者逆时针给出的~~~
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h> using namespace std ; struct node
{
double x;
double y ;
} p[],temp[],newp[];//p是最开始的多边形的每个点,temp是中间过程中临时存的多边形的每个点,newp是切割后的多边形的每个点
int n,newn ;//原来的点数,切割后的点数
double a,b,c ;//直线方程的三个系数 void getline(node x,node y)//求x与y两点确定的直线方程ax+by+c=0
{
a = y.y-x.y ;
b = x.x-y.x ;
c = y.x*x.y - y.y*x.x ;
}
node intersect(node x,node y)//求x与y点确定的直线与ax+by+c=0这条直线的交点
{
double u = a*x.x+b*x.y+c ;
double v = a*y.x+b*y.y+c ;
node t ;
t.x = (x.x*v+y.x*u)/(u+v) ;//y.y-x.y=u+v;y.y-t.y=v;y.y-x.y=u;
t.y = (x.y*v+y.y*u)/(u+v) ;
return t ;
}
void cut()
{
int cutn = ;
for(int i = ; i <= newn ; i++)
{
if(a*newp[i].x+b*newp[i].y+c >= )//所有的点都大于0,说明所有的点都在这条直线的另一边,所以不用切
temp[ ++cutn] = newp[i] ;
else
{
if(a*newp[i-].x+b*newp[i-].y+c > )
temp[++cutn ] = intersect(newp[i-],newp[i]) ;//把新交点加入
if(a*newp[i+].x+b*newp[i+].y+c > )
temp[ ++cutn] = intersect(newp[i+],newp[i]) ;
}
}
for(int i = ; i <= cutn ; i++)
newp[i] = temp[i] ;
newp[cutn+] = temp[] ;//能够找出所有点的前驱和后继
newp[] = temp[cutn] ;
newn = cutn ;
} void solve()
{
for(int i = ; i <= n ; i++)
{
newp[i] = p[i] ;
}
p[n+] = p[] ;
newp[n+] = newp[] ;
newp[] = newp[n] ;
newn = n ;
for(int i = ; i <= n ; i++)
{
getline(p[i],p[i+]) ;//从头开始顺序遍历两个相邻点。
cut() ;
} }
int main()
{
int T ;
scanf("%d",&T) ;
while(T--)
{
scanf("%d",&n) ;
for(int i = ; i <= n ; i++)
scanf("%lf %lf",&p[i].x,&p[i].y) ;
solve() ;
if(newn == ) puts("NO") ;
else puts("YES") ;
}
return ;
}
POJ 3335 Rotating Scoreboard(半平面交求多边形核)的更多相关文章
- POJ 3335 Rotating Scoreboard 半平面交求核
LINK 题意:给出一个多边形,求是否存在核. 思路:比较裸的题,要注意的是求系数和交点时的x和y坐标不要搞混...判断核的顶点数是否大于1就行了 /** @Date : 2017-07-20 19: ...
- POJ 1279 Art Gallery 半平面交求多边形核
第一道半平面交,只会写N^2. 将每条边化作一个不等式,ax+by+c>0,所以要固定顺序,方便求解. 半平面交其实就是对一系列的不等式组进行求解可行解. 如果某点在直线右侧,说明那个点在区域内 ...
- POJ 1279 Art Gallery(半平面交求多边形核的面积)
题目链接 题意 : 求一个多边形的核的面积. 思路 : 半平面交求多边形的核,然后在求面积即可. #include <stdio.h> #include <string.h> ...
- poj 3335 Rotating Scoreboard - 半平面交
/* poj 3335 Rotating Scoreboard - 半平面交 点是顺时针给出的 */ #include <stdio.h> #include<math.h> c ...
- poj 3335 Rotating Scoreboard(半平面交)
Rotating Scoreboard Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6420 Accepted: 25 ...
- POJ 3130 How I Mathematician Wonder What You Are! /POJ 3335 Rotating Scoreboard 初涉半平面交
题意:逆时针给出N个点,求这个多边形是否有核. 思路:半平面交求多边形是否有核.模板题. 定义: 多边形核:多边形的核可以只是一个点,一条直线,但大多数情况下是一个区域(如果是一个区域则必为 ).核内 ...
- poj 3335 Rotating Scoreboard (Half Plane Intersection)
3335 -- Rotating Scoreboard 给出一个多边形,要求判断它的内核是否存在. 还是半平面交的题,在这道题中,公告板允许其所在位置与直线共线也算是可见,于是我们就可以将每一条直线微 ...
- POJ 3335 Rotating Scoreboard(半平面交 多边形是否有核 模板)
题目链接:http://poj.org/problem? id=3335 Description This year, ACM/ICPC World finals will be held in a ...
- poj 3335 Rotating Scoreboard
http://poj.org/problem?id=3335 #include <cstdio> #include <cstring> #include <algorit ...
随机推荐
- hdu 5249 KPI
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5249 KPI Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了 ...
- [转]Asp.net三种事务处理
事务处理是在数据处理时经常遇到的问题,经常用到的方法有以下三种总结整理如下:方法1:直接写入到sql 中在存储过程中使用 BEGIN TRANS, COMMIT TRANS, ROLLBACK TRA ...
- PID
http://blog.gkong.com/liaochangchu_117560.ashx
- 位bit——字节Byte???
1.换算 每8个位(bit)组成一个字节(byte) 位bit简写为小写字母“b”,字节Byte简写为大写字母“B” 8*b=1*B 1024*B=1*KB 1024*K=1MB 2.举例 一个英文字 ...
- java 静态变量生命周期(类生命周期)
Static: 加载:java虚拟机在加载类的过程中为静态变量分配内存. 类变量:static变量在内存中只有一个,存放在方法区,属于类变量,被所有实例所共享 销毁:类被卸载时,静态变量被销毁,并释放 ...
- P3408: [Usaco2009 Oct]Heat Wave 热浪
水题,裸的最短路. ; type link=^node; node=record t,d:longint; f:link; end; var n,m,s,i,j,u,v,w,max:longint; ...
- Windows Phone 8 实现列表触底加载
[背景] 很多时候在做WP开发的过程中会遇到数据需要分页获取,根据微软官方的推荐方式,建议实现为Market中类似的体验,即滑动到列表的底部的时候加载更多的数据. 这一需求在早起WP7.1时代实现起来 ...
- 【扩展】Canvas绘制列表的尝试
传送:http://www.alloyteam.com/2015/10/canvas-attempts-to-draw-list/ 来自:on 2015年10月30日 by TAT.Cson view ...
- SPFA 原理剖析代码实现分析比较
算法简介 SPFA(Shortest Path Faster Algorithm)是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算. 算法流程 算法大致流程是用一个队列来进行维护. ...
- 【BZOJ】【1211】【HNOI2004】树的计数
Prufer序列+组合数学 嗯哼~给定每个点的度数!求树的种数!那么很自然的就想到是用prufer序列啦~(不知道prufer序列的……自己再找找资料吧,这里就不放了,可以去做一下BZOJ1005明明 ...