博客原文地址:http://blog.youkuaiyun.com/xuechelingxiao/article/details/39178777
题目大意:按顺时针或逆时针给出多边形的顶点坐标、圆的半径及圆心坐标。
1.求多边形是否是个凸包,若不是输出“HOLE IS ILL-FORMED”。
2.如果多边形为凸包,判定圆是否在凸包内,若凸包在园内,输出“PEG WILL FIT”,若不在,输出“PEG WILL NOT FIT”。
解题思路:这题大体思路就是用叉积判断一个多边形是不是凸包,因为没告诉给出的点是什么顺序,所以需要判断一下顺时针还是逆时针,还有就是凸包边上的要考虑。
在判断圆是否在凸包内的时候,再用一下叉积,看圆心与凸包叉积是不是一直同号就OK了,再求一下圆心到凸包的每个边的距离是否小于等于圆的半径r(注意这里是小于等于)。 大体上就这些trick,具体见代码吧。
另外放个小福利:WA的同学可以看一下http://midatl.fireduck.com/archive/2003/problems/MidAtlantic-2003/problem-D/
代码如下:
#include <stdio.h>
#include <algorithm>
#include <math.h>
const double eps = 1e-8;
using namespace std;
struct Point {
double x, y;
} P[2000], O;
struct Line {
Point a, b;
} ;
int dcmp(double x) {
return x < -eps ? -1 : x > eps;
}
double xmult(Point a, Point b, Point c) {
return (a.x-c.x)*(b.y-c.y) - (a.y-c.y)*(b.x-c.x);
}
double Distance(Point a, Point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double disptoseg(Point p, Line l){
Point t = p;
t.x += l.a.y-l.b.y, t.y += l.b.x-l.a.x;
if(xmult(l.a,t,p)*xmult(l.b,t,p)>eps)
return Distance(p,l.a) < Distance(p,l.b)
? Distance(p,l.a) : Distance(p,l.b);
return fabs(xmult(p, l.a, l.b))/Distance(l.a, l.b);
}
int main()
{
int n;
double r;
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", &P[i].x, &P[i].y);
}
int Max = -2, Min = 2;
for(int i = 1; i < n; ++i) {
int t = dcmp(xmult(P[i], P[(i+2)%n], P[(i+1)%n]));
Max = max(Max, t), Min = min(Min, t);
}
if(Max+Min != 0) {
int flag = 2;
for(int i = 0; i < n; ++i) {
if(dcmp(disptoseg(O, Line{P[i], P[(i+1)%n]})-r) < 0){
flag--;
break;
}
}
for(int i = 0; i < n; ++i) {
if(Min == -1){
if(dcmp(xmult(P[(i+1)%n], O, P[i])) != 1) {
flag--;
break;
}
}
else {
if(dcmp(xmult(P[(i+1)%n], O, P[i])) != -1) {
flag--;
break;
}
}
}
if(flag == 2) {
printf("PEG WILL FIT\n");
}
else {
printf("PEG WILL NOT FIT\n");
}
}
else {
printf("HOLE IS ILL-FORMED\n");
}
}
return 0;
}