一.原题链接:
http://poj.org/problem?id=1584
二.题目大意:
抽象出来就是给出一个圆心和半径,再按顺序给出n个点,问:
- 若给出的n个点不能按顺序连成凸包,输出”HOLE IS ILL-FORMED”
- 若给出n个点可以连成凸包,并且给出的圆在凸包内,输出”PEG WILL FIT”
- 若给出n个点可以连成凸包,并且给出的圆不在凸包内,
输出”PEG WILL NOT FIT”
三.解题思路:
显而易见:
1. 先判断是否可以连成凸包
2. 再判断圆心是否在凸包里面
3. 再算出圆心到多边形各边的距离
1,2,3满足上一步才进行下一步。
首先介绍叉乘性质:
对于共起点有序向量二元组
(a⃗ ,b⃗ )
,其旋转方向为:使
a⃗
能够旋转一个小于 180 度的角并与
b⃗
重合的方向。若
a⃗ ×b⃗ <0
,则旋转方向为顺时针,
a⃗ ×b⃗ >0
,为逆时针。
- 判断n个点是否可以依次连成凸包:
对于n个点 p1,p2...pn ,依次连接成向量 p1p2→,...pn−1pn→,pnp1→ 将它们前后做叉乘,如果符号都相同,则这n个点可依次连成凸包。符号都相同说明绕着一个方向旋转,自己想象一下。 - 判断圆心是否在多边形里面:
圆心 o 依次连接多边形的点成向量op1→op2→...opn→ ,将它们前后做叉乘,如果符号都相同,说明圆心在多边形内,有一个为0说明圆心在边上。 - 判断圆是否在多边形里面:
由于之前已经确定圆心在多边形里面,于是圆心到线段距离等于圆心到线段所在直线距离,直接求所有的距离中最短的距离与半径对比就可以了。
四.代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class Main {
static final int MAX_SIZE = 50;
static final double INF = 1e40;
static final double ESP = 1e-4;
static int vertexNum;
static double radius;
static Point circleCenter = new Point();
static Point[] polygonPoints;
static double cross(Vector v1, Vector v2){
return v1.x*v2.y - v2.x*v1.y;
}
static double distToLine(Point p, Line l){
return Math.abs((l.a*p.x + l.b*p.y + l.c)/
Math.sqrt(l.a*l.a + l.b*l.b));
}
static boolean convexHull(){
Vector v1 = new Vector(), v2 = new Vector();
v1.setXY(polygonPoints[0], polygonPoints[1]);
v2.setXY(polygonPoints[1], polygonPoints[2]);
boolean positive;
if(cross(v1, v2) < 0){
positive = false;
} else {
positive = true;
}
for(int i = 1; i < vertexNum-2; i++){
v1.setXY(polygonPoints[i], polygonPoints[i+1]);
v2.setXY(polygonPoints[i+1], polygonPoints[i+2]);
double res = cross(v1, v2);
if(res<0&&positive || res>0&&!positive){
return false;
}
}
v1.setXY(polygonPoints[vertexNum-2], polygonPoints[vertexNum-1]);
v2.setXY(polygonPoints[vertexNum-1], polygonPoints[0]);
double res = cross(v1, v2);
if(res<0&&positive || res>0&&!positive){
return false;
}
return true;
}
static boolean centerInPolygon(){
Vector v1 = new Vector(), v2 = new Vector();
v1.setXY(circleCenter, polygonPoints[0]);
v2.setXY(circleCenter, polygonPoints[1]);
boolean positive;
if(cross(v1, v2) < 0){
positive = false;
} else {
positive = true;
}
for(int i = 1; i < vertexNum-1; i++){
v1.setXY(circleCenter, polygonPoints[i]);
v2.setXY(circleCenter, polygonPoints[i+1]);
double res = cross(v1, v2);
if(res<0&&positive || res>0&&!positive ||
res == 0 && radius > 0){
return false;
}
}
return true;
}
static double getMinDist(){
Line line = new Line();
double[] parameter = new double[3];
double minDist = INF;
for(int i = 0; i < vertexNum-1; i++){
line.setPoint(polygonPoints[i], polygonPoints[i+1]);
line.getParameter(parameter);
minDist = Math.min(minDist, distToLine(circleCenter, line));
}
return minDist;
}
public static void main (String args[]){
Scanner in = new Scanner(System.in);
double x, y;
while(true){
vertexNum = in.nextInt();
if(vertexNum < 3){
break;
}
radius = in.nextDouble();
x = in.nextDouble();
y = in.nextDouble();
circleCenter.setXY(x, y);
polygonPoints = new Point[vertexNum];
for(int i = 0; i < vertexNum; i++){
x = in.nextDouble();
y = in.nextDouble();
polygonPoints[i] = new Point();
polygonPoints[i].setXY(x, y);
}
if(!convexHull()){
System.out.println("HOLE IS ILL-FORMED");
} else if (!centerInPolygon() || radius > getMinDist()){
System.out.println("PEG WILL NOT FIT");
} else{
System.out.println("PEG WILL FIT");
}
}
in.close();
}
}
class Point{
public void setXY(double x, double y) {
this.x = x;
this.y = y;
}
public double x, y;
}
class Segment{
public Point a = new Point();
public Point b = new Point();
}
class Line{
public void setPoint(Point b, Point e){
this.begin = b;
this.end = e;
}
public void getParameter(double[] parameter){
a = begin.y-end.y;
b = end.x-begin.x;
c = begin.x*end.y - end.x*begin.y;
}
public double a, b, c;
public Point begin = new Point();
public Point end = new Point();
}
class Vector{
public void setXY(Point begin, Point end) {
this.x = end.x-begin.x;
this.y = end.y-begin.y;
}
public Vector reVector() {
Vector v = new Vector();
v.x = -x;
v.y = -y;
return v;
}
public double x, y;
}