您的位置:首页 > 其它

POJ 3130 How I Mathematician Wonder What You Are!(半平面交求多边形的核)

2015-09-12 21:05 567 查看

How I Mathematician Wonder What You Are!

Description

After counting so many stars in the sky in his childhood, Isaac, now an astronomer and a mathematician uses a big astronomical telescope and lets his image processing program count stars. The hardest part of the program is to
judge if shining object in the sky is really a star. As a mathematician, the only way he knows is to apply a mathematical definition of
stars.

The mathematical definition of a star shape is as follows: A planar shape
F is star-shaped if and only if there is a point C ∈ F such that, for any point P ∈
F, the line segment CP is contained in F. Such a point C is called a
center of F. To get accustomed to the definition let’s see some examples below.



The first two are what you would normally call stars. According to the above definition, however, all shapes in the first row are star-shaped. The two in the second row are not. For each star shape, a center is indicated with
a dot. Note that a star shape in general has infinitely many centers. Fore Example, for the third quadrangular shape, all points in it are centers.

Your job is to write a program that tells whether a given polygonal shape is star-shaped or not.

Input

The input is a sequence of datasets followed by a line containing a single zero. Each dataset specifies a polygon, and is formatted as follows.

n
x1y1
x2y2

xnyn
The first line is the number of vertices, n, which satisfies 4 ≤
n ≤ 50. Subsequent n lines are the x- and y-coordinates of the
n vertices. They are integers and satisfy 0 ≤ xi ≤ 10000 and 0 ≤
yi ≤ 10000 (i = 1, …, n). Line segments (xi,
yi)–(xi + 1, yi + 1) (i = 1, …,
n − 1) and the line segment (xn, yn)–(x1,
y1) form the border of the polygon in the counterclockwise order. That is, these line segments see the inside of the polygon in the left of their directions.

You may assume that the polygon is simple, that is, its border never crosses or touches itself. You may assume assume that no three edges of the polygon meet at a single point even when they are infinitely extended.

Output

For each dataset, output “
1
” if the polygon is star-shaped and “
0
” otherwise. Each number must be in a separate line and the line should not contain any other characters.

Sample Input
6
66 13
96 61
76 98
13 94
4 0
45 68
8
27 21
55 14
93 12
56 95
15 48
38 46
51 65
64 31
0

Sample Output

1
0


【思路分析】
   求多边形是否有核。所谓核就是多边形内能够“看到”多边形的任意边的任意点的一片区域,就像你想在家里只装一个摄像头便能看到家里的所有地方,你肯定要找到一个合适的区域位置才行,这个区域位置其实就是你家(俯视成平面多边形)的核。
   求多边形的核用到的是半平面交,看似高大上,实际上就是延伸多边形的每一条边往里做射线,再取射线一侧的所有区域(类似线性规划),假设有N条边,那么这N条射线“切割”多边形形成的公共区域就是这多边形的核(当然也有存在没有核的情况)。
   具体的操作为:排序和扫描(类似凸包里面的算法),但是凸包里面用的是栈来存储多边形的结点,而这里用双端队列存储半平面。首先将按极角排序后的前两个半平面入双端队列,每次考虑下一个半平面时,当双端队列顶端的两个半平面的交点在当前半平面之外时,删除队列顶端的半平面,直到双端队列顶端的两个半平面的交点在当前半平面之内时;类似的,当双端队列尾端的两个半平面的交点在当前半平面之外时,删除队列尾端的半平面,直到双端队列尾端的两个半平面的交点在当前半平面之内时。然后再将新半平面入队。最后还需要删除队列两段多余的半平面,方法和新半平面的入队相同。这样下来,当双端队列不为空时就可以判断该多边形存在核。
   再自我补充一点,具体操作的时候需要求两线段的交点,这里用到了一个比较巧妙的方法:比值法。



 

 
   如上图所示,对于向量AB和向量CD,其交点为P,现在要求P的坐标。设S1为三角形ACB的面积,S2为三角形ADB的面积,由叉积的性质可得:S1 = cross(A,B,C) / 2,即向量AB和向量AC叉积的一半(注意结果的正负),同理,S2 = cross(A,D,B)。此外,再做三角形ACB和三角形ADB在AB边上的垂线CE和DF,则S1 = |CE| * |AB| / 2,S2 = |DF| * |AB| / 2,而且注意到两个直角三角形CPE和DPF相似,则得到比例关系:|CP| / |PD|
= |CE| / |DF|  ,此时由以上五个等式得到:S1 / S2 = |CE| / |DF| = |CP| / |PD|。
设P坐标为(xp,yp),则由S1 / S2 = |CP| / |PD|   ==》 (xc - xp) / (xp - xd) = (yc - yp) / (yp - yd) = S1 / S2  ==》 xp = (S1 * xd + S2 * xc) / (S1 + S2)  , yp = (S1 * yd
+ S2 * yc) / (S1 + S2)。

代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 55
#define eps 1e-8
int top,bot,num;
int order[maxn],dq[maxn];
struct Point
{
double x,y;
Point()
{

}
Point(double x1,double y1)
{
x = x1;
y = y1;
}
}points[maxn];
struct Line
{
Point s,e;
double angle;
Line()
{

}
Line(Point s1,Point e1)
{
s = s1;
e = e1;
}
}lines[maxn];

int sgn(double x)
{
if(fabs(x) < eps)
return 0;
if(x < 0)
return -1;
return 1;
}
double cross(Point p0,Point p1,Point p2)
{
return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x);
}
bool cmp(int i,int j)
{
int temp = sgn(lines[i].angle - lines[j].angle);
if(!temp)
{
return sgn(cross(lines[i].s,lines[j].s,lines[j].e)) > 0;
//大于0取向量左半部分为半平面,小于0取右半部分
//cross(p0,p1,p2) > 0 表示p2在p0p1的逆时针方向
//多边形的点是顺时针给出,若为逆时针给出,则为小于0
}
return temp < 0;
}
Point getIntersection(Line l1,Line l2)
{
double s1 = cross(l1.s,l1.e,l2.e);//返回这三点围成的三角形的面积
double s2 = cross(l1.s,l2.s,l1.e);
Point p;
p.x = (s2 * l2.e.x + s1 * l2.s.x) / (s1 + s2);
p.y = (s2 * l2.e.y + s1 * l2.s.y) / (s1 + s2);
return p;
}
bool judge(Line l,Line l1,Line l2)
{
Point p = getIntersection(l1,l2);
return sgn(cross(p,l.s,l.e)) < 0;
}
void addLine(Line l)
{
lines[num] = l;
lines[num].angle = atan2(l.e.y - l.s.y,l.e.x - l.s.x);
order[num] = num;
num++;
}
void halfPaneIntersection()
{
int i,j;
sort(order,order + num,cmp);
for(i = 1,j = 0;i < num;i++)
{
if(sgn(lines[order[i]].angle - lines[order[j]].angle) > 0)
{
order[++j] = order[i];
}
}
num = j + 1;
dq[0] = order[0];
dq[1] = order[1];//前两个直线入双端队列
top = 1;
bot = 0;

for(i = 2;i < num;i++)
{
while(bot < top && judge(lines[order[i]],lines[dq[top - 1]],lines[dq[top]]))
top--;
while(bot < top && judge(lines[order[i]],lines[dq[bot + 1]],lines[dq[bot]]))
bot++;
dq[++top] = order[i];//插入队首
}
while(bot < top && judge(lines[dq[bot]],lines[dq[top - 1]],lines[dq[top]]))
top--;
while(bot < top && judge(lines[dq[top]],lines[dq[bot + 1]],lines[dq[bot]]))
bot++;
}
bool isExit()
{
if(top - bot > 1)
return true;
return false;
}
int main()
{
int n;
while(scanf("%d",&n) != EOF && n)
{
num = 0;
for(int i = 0;i < n;i++)
scanf("%lf %lf",&points[i].x,&points[i].y);
for(int i = 0;i < n;i++)
addLine(Line(points[i],points[(i + 1) % n]));
halfPaneIntersection();
if(isExit())
printf("1\n");
else
printf("0\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: