Problem:
Spiral Footrace

Let us enjoy extraordinary footraces at an athletic field.
Before starting the race, small flags representing checkpoints are set up
at random on the field. Every runner has to pass all the checkpoints one by
one in the spiral order specified below.
The starting point is the southwest corner of the athletic field.

At the starting point, runners are facing north.
During the race, they run clockwise in a spiral passing
every checkpoint as illustrated in the following figure.
When moving from one flag to the next, they take a straight path.
This means that the course of a race is always piecewise linear.

Upon arriving at some flag, a runner has to determine the next flag
among those that are not yet visited.
That flag shall be the one at the smallest angle to the right of the direction
that the runner is facing. When more than two flags are on the same straight
line, the runner visits the nearest flag first.
The goal position is the place of the last visited flag.

Your job is to write a program that calculates the length of the course from
the starting point to the goal, supposing that the course consists of
line segments connected by flags.
The position of each flag is given by a coordinate pair
(xi, yi), which is limited
to the first quadrant. The starting point is fixed to the origin (0, 0) where a
flag is always set up.

Input

The input contains multiple data sets, each representing a collection of
flag positions for a footrace. A data set is given in the following
format.

n

x1 y1

x2 y2

...

xn yn

Here, n is the number of flag positions (1 <= n <= 400).
The position of the i-th flag is given by
(xi, yi), where
xi and yi are integers
in meter between 0 and 500 inclusive.
There may be white spaces (blanks and/or tabs) before, in between, or after
xi and yi.
Once a certain
coordinate pair (xi, yi) is given,
the same one will not appear later in the data set, and the origin (0, 0)
will not appear either.

A data set beginning with n = 0 indicates end of the input.

Output

For each data set, your program should output the length of the running course
in meter. Each length should appear on a separate line, with
one digit to the right of the decimal point, after rounding it to one
decimal place.

Sample Input

8
60 70
20 40
50 50
70 10
10 70
80 90
70 50
100 50
5
60 50
0 80
60 20
10 20
60 80
0

Output for the Sample Input

388.9
250.0

Solution in JAVA (judge verdict: Accepted)

import java.util.*;
import java.awt.geom.*;

public class Main{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);

		while(true){
			int n = sc.nextInt();
			if(n == 0 ) break;

			ps = new Point2D[n+1];

			ps[0] = new Point2D.Double(0,0);
			for(int i=1;i<=n;i++){
				ps[i] = new Point2D.Double(sc.nextDouble(),sc.nextDouble());
			}

			double ans = 0;
			before = null;
			while(ps != null){
				ans += convexHull();
			}

			System.out.printf("%.1f\n",ans);
		}
	}

	private static Point2D[] ps;
	private static Point2D before;

	private static double convexHull(){
		double res = 0;
		int n = ps.length;

		Arrays.sort(ps,new Comparator<Point2D>(){
			public int compare(Point2D o1,Point2D o2){
				if(o1.getX() < o2.getX()) return -1;
				else if(o1.getX() > o2.getX()) return 1;
				else if(o1.getY() < o2.getY()) return -1;
				else if(o1.getY() > o2.getY()) return 1;
				else return 0;
			}
		});

		if(n <= 2){
			if(n == 2) res = ps[0].distance(ps[1]);
			ps = null;
			return res;
		}

		int k = 0;
		Point2D[] ch = new Point2D[2*n];
		LinkedList<Point2D> ot = new LinkedList<Point2D>(Arrays.asList(ps));

		for(int i=0;i<n;ch[k++] = ps[i++]){
			while(k>=2 && Line2D.relativeCCW(ch[k-2].getX(),ch[k-2].getY(),ch[k-1].getX(),ch[k-1].getY(),ps[i].getX(),ps[i].getY()) <= 0){
				k--;
			}
		}

		for(int i=n-2, t=k+1;i>=0;ch[k++]=ps[i--]){
			while(k>=t && Line2D.relativeCCW(ch[k-2].getX(),ch[k-2].getY(),ch[k-1].getX(),ch[k-1].getY(),ps[i].getX(),ps[i].getY()) <= 0){
				k--;
			}
		}

		int start = 0;
		if(before != null){
			for(;!ch[start].equals(before);start++);
		}
		//System.out.println("start:" + start + " " + before);

		if(n < k - 1) k = k / 2 + 1;

		ot.remove(ch[start]);
		for(int i=1;i<k-1;i++){
			int a = (start + i) % (k - 1);
			int b = (start + i - 1) % (k - 1);
			res += ch[b].distance(ch[a]);
			ot.remove(ch[a]);
		}
		before = ch[(start - 1 + (k-1)) % (k - 1)];
		if(!ot.isEmpty()) ot.add(before);

		//System.out.println(k-1);
		//System.out.println(Arrays.toString(Arrays.copyOf(ch,k-1)));

		if(n > k-1)
			ps = (Point2D[])ot.toArray(new Point2D[]{});
		else
			ps = null;

		return res;
	}
}