POJ1584 A Round Peg in a Ground Hole 判断多边形是否为凸多边形,判断凸多边形是否在圆内

转载请注明出处:優YoU http://user.qzone.qq.com/289065406/blog/1309142308

大致题意:

按照顺时针或逆时针方向输入一个n边形的顶点坐标集,先判断这个n边形是否为凸包。

再给定一个圆形(圆心坐标和半径),判断这个圆是否完全在n变形内部。

 

解题思路:

题意已经很直白了。。就是那个思路。。。

注意输入完顶点集后,要封闭多边形,方便后面枚举边。

封闭方法:

定义点集数组Vectex[1~n]记录n个顶点,再令Vectex[0]=Vectex[n],Vectex[n+1]=Vectex[1]

 

1、判断凸包:

由于点集已经按某个时针方向有序,因此可以先定义一个方向系数direction=0

两两枚举n边形的边,用叉积判断这两条边的转向(右螺旋或左螺旋),由于存在散点共线的情况,因此当且仅当叉积的值temp第一次不为0时,direction=temp,direction的值此后不再改变。(direction>0 则为右螺旋逆时针,direction<0则为左螺旋顺时针)

此后继续枚举剩下的边,只要判断direction*temp>=0即可,当存在一个direction*temp<0的边,说明这是凹多边形,就不是凸包了。

2、判断圆心与多边形的关系:

用环顾法:

设圆心为P,逐条枚举n边形的边AB,利用

 

计算PA和PB的夹角,最后求和得到的就是环顾角。

(1) 圆心在多边形内部时,环顾角=±360

(2) 圆心在多边形外部时,环顾角=0

(3) 圆心在多边形边上时(不包括顶点),环顾角=±180

(4) 圆心在多边形顶点时,环顾角为(0,360)之间的任意角,其实就是圆心所在的顶点的两条邻接边的夹角。

3、当圆心在圆内时,判断圆与多边形的关系

设圆心为P,逐条枚举n边形的边AB,利用得到△PAB的面积,

再根据公式S=0.5*|AB|*h,可以得到

枚举所有h与圆的半径R比对,只要所有的边都有R-h>=0,则说明圆在多边形内

 

View Code
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define eps 10e-8
#define pi  acos(-1.0)
int n;

struct point
{
    double x, y;
};

point p[4], peg;
double r;


double crossdet(double x1, double y1, double x2, double y2)
{
    return x1 * y2 - x2 * y1;
}

double cross(point o, point a, point b)
{
    return crossdet(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y);
}

double dotdet(double x1, double y1, double x2, double y2)
{
    return x1 * x2 + y1 * y2;
}

double dot(point o, point a, point b)
{
    return dotdet(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y);
}

int dblcmp(double x)
{
    if( fabs(x) < eps) return 0;
    return  x > 0 ? 1 : -1;
}

double ff(double x)
{
    return x * x;
}

double dis(point a, point b)
{
    return sqrt(ff(a.x - b.x) + ff(a.y - b.y));
}

bool convexbag()//判断多边形是否凸包
{
    int dir = 0, tmp, i;
    for(i = 1; i <= n; i++)
    {
        tmp = dblcmp( cross(p[i], p[i+1], p[i+2]) );
        if(!dir) dir = tmp;
        if(dir * tmp < 0)return 0;
    }
    return 1;
}

bool in()//判断圆心是否在多边形里
{
    double angle = 0;
    int i;
    for(i = 1; i <= n; i++)
        if( dblcmp( cross(peg, p[i], p[i+1]) ) >= 0)

            angle += acos( dot(peg, p[i], p[i+1])/dis(peg, p[i])/dis(peg, p[i+1]) );

        else

            angle -= acos( dot(peg, p[i], p[i+1])/dis(peg, p[i])/dis(peg, p[i+1]) );

    if(  dblcmp(angle + 2 * pi) == 0  ||   dblcmp(angle - 2 * pi) == 0)return 1;

    return 0;
}


bool fit()//判断圆是不是在凸多边形中
{
    int i, k;
    for(i = 1; i <= n; i++)
    {    
        k = dblcmp( fabs( cross(peg, p[i], p[i+1])/dis(p[i], p[i+1]) ) - r  );
        if(k < 0)return 0;
    }
    return 1;
}

int main()
{
    int i, j;
    while( ~scanf("%d", &n) )
    {
        if(n < 3)break;
        scanf("%lf%lf%lf", &r, &peg.x, &peg.y);
        for(i = 1; i <= n; i++)
            scanf("%lf%lf", &p[i].x, &p[i].y);
        p[n + 1].x = p[1].x; p[n + 1].y = p[1].y;
        p[n + 2].x = p[2].x; p[n + 2].y = p[2].y;
        if(!convexbag()){ printf("HOLE IS ILL-FORMED\n"); continue;}
        
         if( fit() && in() ) printf("PEG WILL FIT\n");
         
        else printf("PEG WILL NOT FIT\n");
    
    }
    return 0;
}


 

posted @ 2012-08-20 19:31  To be an ACMan  Views(534)  Comments(0)    收藏  举报