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 JAVA (judge verdict: Wrong Answer)


import java.util.*;
import java.math.BigDecimal;

class Main{
	public static void main(String[] args){
		Scanner stdIn = new Scanner(System.in);
		int n = stdIn.nextInt();
		Point[] query = new Point[n];
		for(int i=0;i<n;i++){
			double x = stdIn.nextDouble();
			double y = stdIn.nextDouble();
			query[i] = new Point(x,y);
		}
		ArrayList<Point> list = query[0].andrewScan(query);
		System.out.println(list.size());
		int count = 0;
		for(int i=0;i<list.size();i++){
			Point z = list.get(i);
			if(z.x<0){
				count++;
			}
			if((int)z.x == 0){
				break;
			}
		}
		for(int i=count;i<list.size()+count;i++){
			Point z = list.get(i%list.size());
			System.out.println((int)z.x+" "+(int)z.y);
		}
	}	
}


class Point{

	public double x,y;
	final double EPS = Math.pow(10,-8);
	final int cutoff = 9;

	Point(double x,double y){
		this.x = x;
		this.y = y;
	}

	double abs(){
		Point a = new Point(0,0);	
		return Math.sqrt(norm(a));	
	}
	double abs( Point a ){
		return Math.sqrt(norm(a));
	}
	double norm( Point a ){	
		return rounding((this.x - a.x) * (this.x - a.x) + (this.y - a.y) * (this.y - a.y));
	}

	void add( Point a ){
		this.x = rounding(this.x + a.x);
		this.y = rounding(this.y + a.y);
	}
	void sub( Point a ){
		this.x = rounding(this.x - a.x);
		this.y = rounding(this.y - a.y);
	}
	void mul( double z){
		this.x = rounding(this.x * z);
		this.y = rounding(this.x * z);
	}
	void div( double z){
		this.x = rounding(this.x / z);
		this.y = rounding(this.x / z);
	}

	Point getCrossPoint( Point a , Point b , Point c ){
		Point d = new Point(this.x,this.y);
		Vector s1 = new Vector(d.x,d.y,a.x,a.y);
		Vector s2 = new Vector(b.x,b.y,c.x,c.y);
		s2.mul(-10000);
		Point b2 = new Point(s2.x+b.x,s2.y+b.y);
		s2.mul(-1);
		Point c2 = new Point(s2.x+c.x,s2.y+c.y);
		double t1 = getDistanceSP(b2,c2);
		double t2 = a.getDistanceSP(b2,c2);
		s1.mul(t1/(t1+t2));
		Vector s3 = new Vector(b.x,b.y,d.x,d.y);
		s3.add(s1);
		return new Point(b.x+s3.x,b.y+s3.y);
	}

	double getDistance( Point a , Point b , Point c ){
		if(intersect(a,b,c)){
			return 0.0;
		}
		Point d = new Point(this.x,this.y);
		double x = Math.min(getDistanceSP(b,c),a.getDistanceSP(b,c));
		double y = Math.min(b.getDistanceSP(a,d),c.getDistanceSP(a,d));
		return Math.min(x,y);
	}
	double getDistanceSP( Point a , Point b ){
		Vector s = new Vector( a.x , a.y , b.x , b.y);
		Vector sa = new Vector( a.x , a.y , this.x , this.y );
		Vector sb = new Vector( b.x , b.y , this.x , this.y );
		if(s.dot(sa)<0.00){
			return abs(a);
		}
		s.mul(-1);
		if(s.dot(sb)<0.00){
			return abs(b);
		}
		return Math.abs(s.cross(sb)/s.abs());
	}

	int CCW( Point a , Point b ){
		Vector sa = new Vector( this.x , this.y , a.x , a.y );
		Vector sb = new Vector( this.x , this.y , b.x , b.y );
		if(sa.cross(sb) > EPS){
			return -1;
		}
		else if(sa.cross(sb) < -EPS){
			return 1;
		}
		else if(sa.dot(sb) < -EPS){
			return -2;
		}
		else if(sa.norm() < sb.norm()){
			return 2;
		}
		else{
			return 0;
		}
	}
	boolean intersect( Point a , Point b , Point c ){
		Point d = new Point(this.x,this.y);
		if(CCW(a,b)*CCW(a,c) <= 0 && b.CCW(c,a)*b.CCW(c,d) <= 0){
			return true;
		}
		else{
			return false;
		}
	}

	int contains( Point[] query ){
		boolean flag1 = false;
		Point p = new Point(this.x,this.y);
		final int l = query.length;
		for(int i=0;i<query.length;i++){
			if(judge(query[i]) || query[i].CCW(query[(i+1)%l],p) == 0){
				flag1 = true;
			}
		}
		boolean flag2 = false;
		for(int i=0;i<query.length;i++){
			Vector v1 = new Vector(this.x,this.y,query[i].x,query[i].y);
			Vector v2 = new Vector(this.x,this.y,query[(i+1)%query.length].x,query[(i+1)%query.length].y);
			if(v1.y<=0 && v2.y>0 && v1.cross(v2)<0){
				flag2 = !flag2;
			}
			else if(v2.y<=0 && v1.y>0 && v2.cross(v1)<0){
				flag2 = !flag2;
			}
		}
		if(flag1){
			return 1;
		}
		else if(flag2){
			return 2;
		}
		return 0;
	}

	void temp( Point a ){
		Point temp = new Point(0,0);
		temp.x = this.x;
		temp.y = this.y;
		this.x = a.x;
		this.y = a.y;
		a.x = temp.x;
		a.y = temp.y;
	}
	void sort( Point[] query ){
		for(int i=0;i<query.length;i++){
			for(int j=0;j<query.length-1-i;j++){
				if(query[j].x > query[j+1].x){
					query[j].temp(query[j+1]);
				}
				else if(query[j].x == query[j+1].x && query[j].y > query[j+1].y){
					query[j].temp(query[j+1]);
				}
			}
		}
	}
	ArrayList<Point> andrewScan( Point[] query ){
		ArrayList<Point> list = new ArrayList<Point>();
		if(query.length<4){
			for(int i=0;i<query.length-1;i++){
				for(int j=i;j<query.length-1;j++){
					if(query[j].y>query[j+1].y){
						query[j].temp(query[j+1]);
					}
					else if(query[j].y == query[j+1].y && query[j].x>query[j+1].x){
						query[j].temp(query[j+1]);
					}
				}
			}
			for(int i=0;i<query.length;i++){
				list.add(query[i]);
			}
		}
		else{
			sort(query);
			ArrayList<Point> list1 = new ArrayList<Point>();
			ArrayList<Point> list2 = new ArrayList<Point>();
			list1.add(query[0]);
			list1.add(query[1]);
			int next = 2;
			while(next<query.length-1){
				if(list1.size()<2){
					list1.add(query[next]);
					next++;
				}
				else{
					Point p1 = list1.get(list1.size()-2);
					Point p2 = list1.get(list1.size()-1);
					if(p1.CCW(p2,query[next])!=-1){
						list1.add(query[next]);
						next++;
					}
					else{
						list1.remove(list1.size()-1);
					}
				}
			}
			boolean flag1 = true;
			while(flag1){
				Point p1 = list1.get(list1.size()-2);
				Point p2 = list1.get(list1.size()-1);
				if(p1.CCW(p2,query[query.length-1])!=-1){
					list1.add(query[query.length-1]);
					flag1 = false;
				}
				else{
					list1.remove(list1.size()-1);
					if(list1.size()<2){
						list1.add(query[query.length-1]);
						flag1 = false;
					}
				}
			}
			list2.add(query[query.length-1]);
			list2.add(query[query.length-2]);
			next = query.length-3;
			while(next>0){
				if(list2.size()<2){
					list2.add(query[next]);
					next--;
				}
				else{
					Point a = list2.get(list2.size()-2);
					Point b = list2.get(list2.size()-1);
					if(a.CCW(b,query[next])!=-1){
						list2.add(query[next]);
						next--;
					}
					else{
						list2.remove(list2.size()-1);
					}
				}
			}
			boolean flag2 = true;
			while(flag2){
				Point p1 = list2.get(list2.size()-2);
				Point p2 = list2.get(list2.size()-1);
				if(p1.CCW(p2,query[0])>=0){
					list2.add(query[0]);
					flag2 = false;
				}
				else{
					list2.remove(list2.size()-1);
					if(list2.size()<2){
						list2.add(query[0]);
						flag2 = false;
					}
				}
			}
			for(int i=list2.size()-1;i>=0;i--){
				list.add(list2.get(i));
			}
			for(int i=list1.size()-2;i>=1;i--){
				list.add(list1.get(i));
			}
		}
		return list;
	}
	double area( Point[] query ){
		double area = 0;
		for(int i=0;i<query.length-1;i++){
			area += (query[i].x - query[i+1].x) * (query[i].y + query[i+1].y)/2;
		}
		area += (query[query.length-1].x - query[0].x) * (query[query.length-1].y + query[0].y)/2;
		area = Math.abs(area);
		return area;
	}

	Point polarCos(double cos_a){
		double sin_a = Math.sqrt(1-Math.pow(cos_a,2));
		double x = cos_a*this.x - sin_a*this.y;
		double y = sin_a*this.x + cos_a*this.y;
		return new Point(x,y); 
	}
	Point polarSin(double sin_a){
		double cos_a = Math.sqrt(1-Math.pow(sin_a,2));
		double x = cos_a*this.x - sin_a*this.y;
		double y = sin_a*this.x + cos_a*this.y;
		return new Point(x,y); 
	}

	boolean judge( Point a ){	
		if( Math.abs( this.x - a.x ) < EPS && Math.abs( this.y - a.y ) < EPS){
			return true;
		}
		else{
			return false;
		}
	}
	double rounding(double a){
		BigDecimal bi = new BigDecimal(String.valueOf(a));
		return bi.setScale(cutoff,BigDecimal.ROUND_HALF_UP).doubleValue();
	}
}
class Vector{
	public final double EPS = Math.pow(10,-8);
	public double x,y;

	Vector( double x1 , double y1 , double x2 , double y2 ){
		this.x = x2 - x1;
		this.y = y2 - y1;
	}

	double dot( Vector a ){	
		return this.x * a.x + this.y * a.y;
	}
	double cross( Vector a ){	
		return this.x * a.y - this.y * a.x;
	}

	void add( Vector a ){
		this.x += a.x;
		this.y += a.y;
	}
	void sub( Vector a ){
		this.x -= a.x;
		this.y -= a.y;
	}
	void mul( double z ){
		this.x *= z;
		this.y *= z;
	}
	void div( double z ){
		this.x /= z;
		this.y /= z;
	}

	double abs(){
		return Math.sqrt(norm());
	}
	double norm(){
		return this.x * this.x + this.y * this.y;
	}

	double cos(Vector a){
		Vector b = new Vector(0,0,this.x,this.y);
		Vector c = new Vector(a.x,a.y,b.x,b.y);
		if(judge(a.dot(b))){
			return 0.0;
		}
		double cos = (Math.pow(a.abs(),2)+Math.pow(b.abs(),2)-Math.pow(c.abs(),2))/(2*a.abs()*b.abs());
		return cos;
	}
	double sin(Vector a){
		Vector b = new Vector(0,0,this.x,this.y);
		if(judge(a.cross(b))){
			return 0.0;
		}
		double height = a.cross(b)/a.abs();
		double sin = b.abs()/height;
		return sin;
	}
	double cosLength( double a , double b , double c ){
		double cos = (Math.pow(a,2) + Math.pow(b,2) - Math.pow(c,2))/(2 * a * b);
		if(judge(cos)){
			return 0.0;
		}
		return cos;
	}
	double sinLength( double a , double b , double c ){
		double cos = cosLength(a,b,c);
		if(judge(1-cos)){
			return 0.0;
		}
		return Math.sqrt(1-Math.pow(cos,2));

	}

	void projection( Vector a ){
		double cos = dot(a)/(abs() * a.abs());
		double frac = a.abs() * cos/abs();
		mul(frac);
	}
	Vector reflection( Vector a ){
		projection(a);
		return new Vector(a.x,a.y,this.x,this.y);
	}

	boolean judgeisOrthogonal( Vector a ){	
		return judge(dot(a)) ? true : false;
	}  
	boolean judgeisParallel( Vector a ){	
		return judge(cross(a)) ? true : false;
	}

	boolean judge( double a ){	
		return Math.abs(a)<EPS ? true : false;
	}
}