题目大意:
顺时针或逆时针给出n个点,问这n个点围成的图形是不是个凸多边形。如果是凸多边形,给一个圆,以圆心的坐标和半径表示,问这个圆是不是完全在凸多边形内部。
解题思路:
1、先判断是不是凸多边形。我们可以通过两个向量的叉积来判断第三个点在前两个点的什么方向。(见《算法艺术与信息学竞赛》第三章)
因为n个点给出时的方向不确定(有可能是顺时针有可能是逆时针),只要相邻两个向量叉积出来的正负是相同的,或者某一个是0,一定是在相同方向.(叉积是0表示两向量共线)。
2、再判断点是否在凸多边形内。如果在凸多边形内的话,对于枚举凸多边形上的每一个点和它的下一个点所组成的向量,与这个点与圆心组成的向量的叉积符号一定是相同的,因为对于凸多边形来说,如果某一个点在其内部的话,一定在其所有边的相同一侧。
3,最后判断圆心到每个边距离的最小值是否大于圆的半径。这个要用到点到直线距离的公式。
4、完成判断后满足什么要求输出什么就行了。
下面是代码:
#include <stdio.h>
#include <math.h>
#define eps 1e-6
int n;
struct node
{
double x,y;
} point[1005],o;
double r;
double min(double a,double b)
{
if(a>b)a=b;
return a;
}
int judge(double x)
{
if(fabs(x)>eps)
{
if(x>0)return 1;
return -1;
}
return 0;
}
double xmult(node a,node b,node c)
{
return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
bool Checkconvex()
{
int a=0,b,i;
for(i=0; i<n; i++)
{
b=judge(xmult(point[i],point[i+1],point[i+2]));
if(!a)a=b;
else if(a&&a*b<0)return true;
}
return false;
}
bool Checkinside()
{
int a,b=judge(xmult(o,point[1],point[0]));
for(int i=1;i<n;i++)
{
a=judge(xmult(o,point[i+1],point[i]));
if(a*b<0)
{
return true;
}
}
return false;
}
double does(node a,node b)//计算点到直线的距离
{
return fabs(xmult(a,b,o))/sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool Checkdist()
{
double dist=1e10;
for(int i=0;i<n;i++)
{
dist=min(dist,does(point[i],point[i+1]));
}
if(judge(dist-r)<0)
{
return true;
}
return false;
}
int main()
{
while(scanf("%d",&n),n>=3)
{
scanf("%lf%lf%lf",&r,&o.x,&o.y);
for(int i=0; i<n; i++)
{
scanf("%lf%lf",&point[i].x,&point[i].y);
}
point[n]=point[0];
point[n+1]=point[1];
if(Checkconvex())//检查是否为凸多边形
{
printf("HOLE IS ILL-FORMED\n");
}
else
{
if(Checkinside()||Checkdist())
{
printf("PEG WILL NOT FIT\n");
}
else
{
printf("PEG WILL FIT\n");
}
}
}
return 0;
}