一.原题链接:
http://poj.org/problem?id=1113
二.题目大意:
给出若干个点,求一条封闭曲线能将所有点包围,并且和所有点和所有点所能连成的线段距离要小于给定长度,要求曲线长度最短,求曲线长度。
三.解题思路:
曲线的长度等价于所有点的凸包加上给定长度为半径的圆。
圆:每个多边形的角为所成的圆弧的内角,围起来再加上凸包的边。
Graham扫描法求凸包:
1. 选
x
值最小,
2. 按
p0p0→,p0p1→,p0p2→...,p0pn−1→
的极角大小升序排序。设排序后点序列为
p′0,p′1,...,p′n
。
3. 维护一个栈:
- 先将 p′0,p′1,p′2 入栈。
- 遍历排好序的点序列,从
p′3
开始遍历,在每次遍历中,设从排序的点序列来的点为
p
,栈顶2个元素分别为
s , t ,t 在最顶部,循环弹栈直到 st→×tp→>=0 遍历完栈中元素为凸包上的点。
对于点 p0,p1,p2 , p0 为基点,要判断 p1,p2 排序的关系,即判断 p0p1→ 与 p0p2→ 的极角大小,只需要求出 p0p1→×p1p2→ ,大于0说明 p2 极角大。
四.代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
class Main {
static final int MAX_SIZE = 1050;
static final double INF = 1e40;
static final double ESP = 1e-4;
static int vertexNum;
static double length;
static List<Point> points = new ArrayList<Point>();
static Point base;
static Stack<Point> s;
static double cross(Vector v1, Vector v2){
return v1.x*v2.y - v2.x*v1.y;
}
static double pointDist(Point p1, Point p2){
return Math.sqrt((p1.x-p2.x)*(p1.x-p2.x) +
(p1.y-p2.y)*(p1.y-p2.y));
}
static void sortPoints(){
Collections.sort(points, new Comparator(){
@Override
public int compare(Object arg0, Object arg1) {
Point p1 = (Point)arg0;
Point p2 = (Point)arg1;
Vector v1 = new Vector();
Vector v2 = new Vector();
v1.setXY(base, p1);
v2.setXY(p1, p2);
double res = cross(v1, v2);
if(res > 0){
return -1;
}else if(res == 0){
return (pointDist(p1, base) >
pointDist(p2, base)? 1:-1);
}else{
return 1;
}
}
});
}
static void findConvexHull(){
s = new Stack<Point>();
s.push(points.get(0));
s.push(points.get(1));
s.push(points.get(2));
for(int i = 3; i < vertexNum; i++){
while(true){
Point beJudged = s.pop();
Point begin = s.peek();
Vector v1 = new Vector(), v2 = new Vector();
v1.setXY(begin, beJudged);
v2.setXY(beJudged, points.get(i));
if(cross(v1, v2)>=0){
s.push(beJudged);
break;
}
}
s.push(points.get(i));
}
}
public static void main (String args[]){
Scanner in = new Scanner(System.in);
double x, y;
while(in.hasNext()){
vertexNum = in.nextInt();
length = in.nextDouble();
int baseIdx = 0;
points.removeAll(points);
for(int i = 0; i < vertexNum; i++){
x = in.nextDouble();
y = in.nextDouble();
Point p = new Point();
p.setXY(x, y);
points.add(p);
if(points.get(baseIdx).y > y ||
points.get(baseIdx).y == y &&
points.get(baseIdx).x > x){
baseIdx = i;
}
}
base = points.get(baseIdx);
sortPoints();
findConvexHull();
double res = pointDist(base, s.peek());
while(s.size() > 1){
Point p = s.pop();
res += pointDist(p, s.peek());
}
Point p = s.pop();
res += pointDist(p, base);
res += 2*Math.PI*length;
System.out.println(Math.round(res));
}
in.close();
}
}
class Point{
public void setXY(double x, double y) {
this.x = x;
this.y = y;
}
public double x, y;
}
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;
}