poj3130——半平面交(逆时针)

题目链接:http://poj.org/problem?id=3130

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

题目翻译:

‎艾萨克在童年时计算了天空中的这么多恒星后,现在还是一位天文学家和数学家,他使用一台大型天文望远镜,让他的图像处理程序计算星星。程序最难的部分是判断天空中闪亮的物体是否真的是一颗星星。作为一个数学家,他知道的唯一方法是应用‎‎恒星‎‎的数学定义。‎

‎星形的数学定义如下:平面形状‎‎F‎‎是‎‎星形‎‎的,如果并且仅当有一个点 C * ‎‎F,‎‎因此,对于任何点 P * ‎‎F,‎‎线段 CP 包含在‎‎F‎‎中。这样的点C‎‎被称为F‎‎的中心。‎‎为了适应这个定义,让我们看下面的一些例子。‎

 

‎前两个是你通常所说的星星。但是,根据上述定义,第一行中的所有形状都是星形的。第二行中的两个不是。对于每个星形形状,用点指示中心。请注意,星形通常具有无限多个中心。例如,对于第三个四边形形状,其中的所有点都是中心。‎

‎你的工作是编写一个程序,告诉给定的多边形形状是否为星形。‎

‎输入‎

‎输入是数据集序列,后跟包含单个零的行。每个数据集指定一个面,并采用如下格式。‎

n 
x1y1
x2y2

‎...‎

xn‎y‎‎n n‎

‎第一行是顶点数‎‎n‎‎,满足 4 = ‎‎n‎‎ = 50。后续‎‎n‎‎条线是‎‎n‎‎顶点的‎‎x‎‎和‎‎y‎‎坐标。它们是整数,满足 0 = ‎‎x‎‎i‎‎ ‎‎ = 10000 和 0 = ‎‎y‎‎i‎‎ ‎‎ = 10000‎‎(i‎‎ = 1, ..., ‎‎n‎‎)。线段 (‎‎x‎‎i‎‎, ‎‎y‎‎i‎‎) * (‎‎x‎‎i‎‎ ‎‎ ‎‎ = 1‎‎, ‎‎y‎‎i‎‎ ‎‎ ‎‎ = 1‎‎) (‎‎i‎‎ = 1, ..., ‎‎n‎‎ = 1) 和线段 (‎‎x‎‎n‎‎ ‎‎, ‎‎y‎‎n‎‎) (‎‎x‎‎1‎‎, ‎‎y‎‎1‎‎) 以逆时针顺序形成多边形的边框。也就是说,这些线段在其方向的左侧看到多边形的内部。‎

‎你可以假设多边形‎‎很简单,‎‎也就是说,它的边框从不交叉或触及自身。您可能假定多边形的三条边在单个点上没有相交,即使它们无限扩展。‎

‎输出‎

‎对于每个数据集,如果多边形为星形,则输出"",否则输出为""。每个数字必须位于单独的行中,并且该行不应包含任何其他字符。‎

 

经典半平面交例题,只不过输入数据顺序定了,为逆序输出,其他和上一个题差不多:poj3335——半平面交模板(方向不定)

#include<iostream>
#include<cmath> 
#include<algorithm>
using namespace std;
const double eps = 1e-8;
const int inf=0x3f3f3f3f;
struct Point{
    double x, y;
    Point(double x = 0, double y = 0):x(x),y(y){}
}p[1005];
int n;
typedef Point Vector;
Vector operator + (Vector A, Vector B){
    return Vector(A.x+B.x, A.y+B.y);
}
Vector operator - (Point A, Point B){
    return Vector(A.x-B.x, A.y-B.y);
}
Vector operator * (Vector A, double p){
    return Vector(A.x*p, A.y*p);
}
int sgn(double x){
    if(fabs(x) < eps)
        return 0;
    if(x < 0)
        return -1;
    return 1;
}
double Dot(Vector A, Vector B){
    return A.x*B.x + A.y*B.y;
}
double Cross(Vector A, Vector B){
    return A.x*B.y-A.y*B.x;
}
double Length(Vector A){
    return sqrt(Dot(A, A));
}
Vector Normal(Vector A){//向量A左转90°的单位法向量
    double L = Length(A);
    return Vector(-A.y/L, A.x/L);
}
struct Line{
    Point p;//直线上任意一点
    Vector v;//方向向量,它的左边就是对应的半平面
    double ang;//极角,即从x轴正半轴旋转到向量v所需要的角(弧度)
    Line(){}
    Line(Point p, Vector v) : p(p), v(v){
        ang = atan2(v.y, v.x);
    }
    bool operator < (const Line& L) const {//排序用的比较运算符
        return ang < L.ang;
    }
}l[1005];
//点p在有向直线L的左侧
bool OnLeft(Line L, Point p){
    return Cross(L.v, p - L.p) >= 0;
}
//两直线交点。假定交点唯一存在
Point GetIntersection(Line a, Line b){
    Vector u = a.p - b.p;
    double t = Cross(b.v, u)/Cross(a.v, b.v);
    return a.p + a.v*t;
}
//半平面交的主过程
int HalfplaneIntersection(Line* L, int n, Point* poly){
    sort(L, L + n);//按照极角排序
    int fst = 0, lst = 0;//双端队列的第一个元素和最后一个元素
    Point *P = new Point[n];//p[i] 为 q[i]与q[i + 1]的交点
    Line *q = new Line[n];//双端队列
    q[fst = lst = 0] = L[0];//初始化为只有一个半平面L[0]
    for(int i = 1; i < n; ++i){
        while(fst < lst && !OnLeft(L[i], P[lst - 1])) --lst;
        while(fst < lst && !OnLeft(L[i], P[fst])) ++fst;
        q[++lst] = L[i];
        if(sgn(Cross(q[lst].v, q[lst - 1].v)) == 0){
            //两向量平行且同向,取内侧一个
            --lst;
            if(OnLeft(q[lst], L[i].p)) q[lst] = L[i];
        }
        if(fst < lst)
            P[lst - 1] = GetIntersection(q[lst - 1], q[lst]);
    }
    while(fst < lst && !OnLeft(q[fst], P[lst - 1])) --lst;
    //删除无用平面
    if(lst - fst <= 1) return 0;//空集
    P[lst] = GetIntersection(q[lst], q[fst]);//计算首尾两个半平面的交点
    //从deque复制到输出中
    int m = 0;
    for(int i = fst; i <= lst; ++i) poly[m++] = P[i];
    return m;
}
int main(){
	while(~scanf("%d",&n)&&n){
		for(int i=n-1;i>=0;i--)
			scanf("%lf%lf",&p[i].x,&p[i].y);
		l[0]=Line(p[0],p[n-1]-p[0]);
		for(int i=1;i<n;i++)
			l[i]=Line(p[i], p[i-1]-p[i]);
		int res=HalfplaneIntersection(l,n,p);
		if(!res) printf("0\n");
		else printf("1\n");
	}
	return 0;
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值