Problem:
Convex Hull

Find the convex hull of a given set of points P. In other words, find the smallest convex polygon containing all the points of P. Here, in a convex polygon, all interior angles are less than or equal to 180 degrees.

Please note that you should find all the points of P on both corner and boundary of the convex polygon.

Input

n
x1 y1
x2 y2
:
xn yn

The first integer n is the number of points in P. The coordinate of the i-th point pi is given by two integers xi and yi.

Output

In the first line, print the number of points on the corner/boundary of the convex polygon. In the following lines, print x y coordinates of the set of points.
The coordinates should be given in the order of counter-clockwise visit of them starting from the point in P with the minimum y-coordinate, or the leftmost such point in case of a tie.

Constraints

3 ≤ n ≤ 100000

-10000 ≤ xi, yi ≤ 10000

No point in the P will occur more than once.

Sample Input 1

7
2 1
0 0
1 2
2 2
4 2
1 3
3 3

Sample Output 1

5
0 0
2 1
4 2
3 3
1 3

Sample Input 2

4
0 0
2 2
0 2
0 1

Sample Output 2

4
0 0
2 2
0 2
0 1

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CGL_4_A_Convex_Hull
{
	class Program
	{
		static void Main ( string[] args )
		{
			int inputCount = int.Parse (Console.ReadLine ());
			Vector2[] polygon = new Vector2[inputCount];

			for (int lp = 0; lp < inputCount; lp++)
			{
				decimal[] i = Array.ConvertAll (Console.ReadLine ().Split (' '), decimal.Parse);
				polygon[lp] = new Vector2 (i[0], i[1]);
			}

			var result = Vector2.ConvexHull (polygon);
			int index = 0;

			for (int lp = 1; lp < result.Length; lp++)
			{
				if (result[lp].Y < result[index].Y)
				{
					index = lp;
				}
			}

			StringBuilder output = new StringBuilder (result.Length * 9);

			output.Append (result.Length);
			output.AppendLine ();

			for (int lp = index; lp < index + result.Length; lp++)
			{
				var item = result[lp % result.Length];

				output.Append (item.X);
				output.Append (" ");
				output.Append (item.Y);
				output.AppendLine ();
			}

			Console.Write (output);
		}
	}

	class Vector2
	{
		public Vector2 ( decimal x, decimal y )
		{
			this.X = x;
			this.Y = y;
		}

		public decimal X { private set; get; }
		public decimal Y { private set; get; }

		public static Vector2 operator - ( Vector2 ob1, Vector2 ob2 )
		{
			return new Vector2 (ob1.X - ob2.X, ob1.Y - ob2.Y);
		}

		public decimal Length ()
		{
			return X * X + Y * Y;
		}
		public static decimal DotProduct ( Vector2 line1, Vector2 line2 )
		{
			return line1.X * line2.X + line1.Y * line2.Y;
		}
		public static decimal CrossProduct ( Vector2 line1, Vector2 line2 )
		{
			return line1.X * line2.Y - line1.Y * line2.X;
		}

		public const int Counter_Clockwise = 1;
		public const int Clockwise = -1;
		public const int OnlineBack = 2;
		public const int OnlineFront = -2;
		public const int OnSegment = 0;

		public static int PointState ( Vector2 point1, Vector2 point2, Vector2 point3 )
		{
			Vector2 line1 = point2 - point1;
			Vector2 line2 = point3 - point1;

			decimal crossProduct = CrossProduct (line1, line2);

			if (crossProduct > 0m)
			{
				return Counter_Clockwise;
			}
			else if (crossProduct < 0m)
			{
				return Clockwise;
			}
			else if (DotProduct (line1, line2) < 0m)
			{
				return OnlineBack;
			}
			else if (line1.Length () < line2.Length ())
			{
				return OnlineFront;
			}

			return OnSegment;
		}

		public static Vector2[] ConvexHull ( Vector2[] polygon )
		{
			polygon = polygon.OrderBy (item => item.X).ThenBy (item => item.Y).ToArray ();
			int count = polygon.Length;

			//上部
			List<Vector2> topPoint = new List<Vector2> (count);
			topPoint.Add (polygon[0]);
			topPoint.Add (polygon[1]);

			for (int lp = 2; lp < count; lp++)
			{
				for (int n = topPoint.Count; 2 <= n && 0 <= Vector2.PointState (topPoint[n - 2], topPoint[n - 1], polygon[lp]); n--)
				{
					topPoint.RemoveAt (n - 1);
				}

				topPoint.Add (polygon[lp]);
			}

			//下部
			List<Vector2> buttomPoint = new List<Vector2> (count);
			buttomPoint.Add (polygon[count - 1]);
			buttomPoint.Add (polygon[count - 2]);

			for (int lp = count - 3; 0 <= lp; lp--)
			{
				for (int n = buttomPoint.Count; 2 <= n && 0 <= Vector2.PointState (buttomPoint[n - 2], buttomPoint[n - 1], polygon[lp]); n--)
				{
					buttomPoint.RemoveAt (n - 1);
				}

				buttomPoint.Add (polygon[lp]);
			}

			//結合
			buttomPoint.Reverse ();

			for (int lp = topPoint.Count - 2; 1 <= lp; lp--)
			{
				buttomPoint.Add (topPoint[lp]);
			}

			return buttomPoint.ToArray ();
		}
	}

}