# HDU1392(凸包）

## 题目

There are a lot of trees in an area. A peasant wants to buy a rope to surround all these trees. So at first he must know the minimal required length of the rope. However, he does not know how to calculate it. Can you help him?
The diameter and length of the trees are omitted, which means a tree can be seen as a point. The thickness of the rope is also omitted which means a rope can be seen as a line.

Input

The input contains one or more data sets. At first line of each input data set is number of trees in this data set, it is followed by series of coordinates of the trees. Each coordinate is a positive integer pair, and each integer is less than 32767. Each pair is separated by blank.
Zero at line for number of trees terminates the input for your program.

Output

The minimal length of the rope. The precision should be 10^-2.

Sample Input

9
12 7
24 9
30 5
41 9
80 7
50 87
22 9
45 1
50 7
0

Sample Output

243.06

## 思路

#### 相关概念

##### 向量积

\vec{x} \times \vec{y} = |x||y|sinO \vec{n}

#### Andrew算法

1. 首先排序所有的点，主关键字为x,副关键字为y
2. 将第一个点，第二点加入凸包栈中
3. 从第三个点开始，判断这个点是否在当前凸包的前进方向，也就是栈顶两个点构成向量的左边，若是则继续
4. 否则，则会依次弹出栈顶顶点，重复第3步，直到当前的点符合前进的方向。
5. 考察所有点，这样我们找到只是凸包的下边界，所以从最后一个点开始，倒着再来一遍，得到上边界。
6. 这样，我们就得到了凸包的所有的点

## 代码

package com.special.HDU;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

/**
* Created by Special on 2018/5/18 13:45
*/
public class HDU1392 {

static class Node{
int x, y;
public Node(int x, int y){
this.x = x;
this.y = y;
}

/**
* 两点形成一个向量
* @param node
* @return
*/
public Node vector(Node node){
return new Node(this.x - node.x, this.y - node.y);
}
}

/**
* 向量积
* @param o1
* @param o2
* @return
*/
static int crossProduct(Node o1, Node o2){
return o1.x * o2.y - o1.y * o2.x;
}

/**
* 欧式距离
* @param o1
* @param o2
* @return
*/
static double distance(Node o1, Node o2){
return Math.sqrt(Math.pow(o1.x - o2.x, 2) + Math.pow(o1.y - o2.y, 2));
}

public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n;
while(input.hasNext()) {
n = input.nextInt();
if (n == 0) {
break;
}
Node[] nodes = new Node[n];
Node[] emboss = new Node[2 * n];
for (int i = 0; i < n; i++) {
nodes[i] = new Node(input.nextInt(), input.nextInt());
}
if (n == 2) { //坑爹的题目
System.out.println(String.format("%.2f", distance(nodes[0], nodes[1])));
} else {
Arrays.sort(nodes, new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
if (o1.x != o2.x) {
return o1.x - o2.x;
} else {
return o1.y - o2.y;
}
}
});
int m = 0;
for (int i = 0; i < n; i++) { //下边界
while (m > 1 && (crossProduct(emboss[m - 1].vector(emboss[m - 2]), nodes[i].vector(emboss[m - 2])) < 0)) {
m--;
}
emboss[m++] = nodes[i];
}
int k = m;
for (int i = n - 2; i >= 0; i--) { //上边界
while (m > k && (crossProduct(emboss[m - 1].vector(emboss[m - 2]), nodes[i].vector(emboss[m - 2])) < 0)) {
m--;
}
emboss[m++] = nodes[i];
}
double sum = 0;
//注意这里凸包里最后一个已经是第一个点了，所以最后不用单独求最后一点与最开始点的距离
for (int i = 1; i < m; i++) {
sum += distance(emboss[i], emboss[i - 1]);
}
System.out.println(String.format("%.2f", sum));
}
}
}
}