鏈接:https://cn.vjudge.net/problem/POJ-1584
題意:判斷多邊形是否爲凸多邊形以及圓是否在多邊形內。
思路:模板。詳情看註釋。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 1e3+10;
const double eps = 1e-8;
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x>0) return 1;
else return -1;
}
struct Point
{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
Point operator -(const Point& a)const
{
return Point(x-a.x,y-a.y);
}
double operator ^(const Point& a)const
{
return x*a.y-y*a.x;
}
double operator *(const Point& a)const
{
return x*a.x+y*a.y;
}
}ps[N],peg;
struct Line
{
Point s,e;
Line(){}
Line(Point ss,Point ee)
{
s=ss,e=ee;
}
};
int n,pos,top;
bool no;
double pr,x,y;
//兩點距離
double dis(Point a,Point b)
{
return sqrt((b-a)*(b-a));
}
//以0爲標準,極角排序
bool cmp(const Point& a,const Point& b)
{
x=(a-ps[0])^(b-ps[0]);
if(sgn(x)==0)
{
return dis(ps[0],a)<dis(ps[0],b);
}
else if(x>0) return 1;
else return 0;
}
//是否爲凸多邊形
//可有共線邊
bool isconv()
{
bool s[3];
s[0]=s[1]=s[2]=0;
for(int i=0;i<n;i++)
{
s[sgn( (ps[(i+1)%n]-ps[i])^(ps[(i+2)%n]-ps[i]) )+1]=1;
if(s[0]&&s[2]) return 0;
}
return 1;
}
//點是否在線段上
bool OnSeg(Point P,Line L)
{
return
sgn((L.s-P)^(L.e-P)) == 0 &&
sgn((P.x - L.s.x) * (P.x - L.e.x)) <= 0 &&
sgn((P.y - L.s.y) * (P.y - L.e.y)) <= 0;
}
//線段是否相交
bool inter(Line l1,Line l2)
{
return
max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&
max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&
max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&
max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&
sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0 &&
sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0;
}
//點是否在多邊形內
//引射線判斷法
//返回值
//-1:點在凸多邊形外
//0:點在凸多邊形邊界上
//1:點在凸多邊形內
int inPoly(Point p,Point poly[],int n)
{
int cnt;
Line ray,side;
cnt = 0;
ray.s = p;
ray.e.y = p.y;
ray.e.x = -100000000000.0;//-INF,注意取值防止越界
for(int i = 0;i < n;i++)
{
side.s = poly[i];
side.e = poly[(i+1)%n];
if(OnSeg(p,side))return 0;
//如果平行軸則不考慮
if(sgn(side.s.y - side.e.y) == 0)
continue;
if(OnSeg(side.s,ray))
{
if(sgn(side.s.y - side.e.y) > 0)cnt++;
}
else if(OnSeg(side.e,ray))
{
if(sgn(side.e.y - side.s.y) > 0)cnt++;
}
else if(inter(ray,side))
cnt++;
}
if(cnt % 2 == 1)return 1;
else return -1;
}
bool inconv()
{
for(int i=0;i<n;i++)
if(sgn((ps[i]-peg)^(ps[(i+1)%n]-peg))<=0) return 0;
return 1;
}
//判斷點是否在凸多邊形內
//這個題不能用,不知道爲啥。
int inConvexPoly(Point a,Point p[],int n)
{
for(int i = 0;i < n;i++)
{
if(sgn((p[i]-a)^(p[(i+1)%n]-a)) < 0)return -1;
else if(OnSeg(a,Line(p[i],p[(i+1)%n])))return 0;
}
return 1;
}
int main(void)
{
while(~scanf("%d",&n)&&(n>=3))
{
no=0;
scanf("%lf%lf%lf",&pr,&peg.x,&peg.y);
pos=0;
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&ps[i].x,&ps[i].y);
if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
pos=i;
}
if(!isconv())
{
puts("HOLE IS ILL-FORMED");
continue;
}
swap(ps[0],ps[pos]);
sort(ps+1,ps+n,cmp);
if(inPoly(peg,ps,n)<0)
{
puts("PEG WILL NOT FIT");
continue;
}
//以下兩種判斷點是否在凸多邊形內的方法
//對於此題都不行
/*
if(inConvexPoly(peg,ps,n)<=0)
{
puts("PEG WILL NOT FIT");
continue;
}*/
/*
if(!inconv())
{
puts("PEG WILL NOT FIT");
continue;
}*/
double d;
for(int i=0;i<n;i++)
{
d=fabs((peg-ps[i])^(ps[(i+1)%n]-ps[i]))/dis(ps[i],ps[(i+1)%n]);
if(sgn(d-pr)<0)
{
no=1;
break;
}
}
if(no)
puts("PEG WILL NOT FIT");
else puts("PEG WILL FIT");
}
return 0;
}