// c.durr - 2015 - upmc
// streaming algorithms

import java.util.*;
import java.io.*;

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

	double dist(Point q) {
		return Math.hypot(x-q.x, y-q.y);
	}

	double dist(ArrayList<Point> S) {   // distance avec le point le plus proche dans S
		double distmin = Double.MAX_VALUE;
		for (Point q: S) {
			double d = dist(q);
			if (d<distmin)
				distmin = d;
		}
		return distmin;
	}

	public String toString() {return x + " "+y;} // pour affichage
}


class FluxPoints {
	Scanner in;

	FluxPoints(String filename) throws FileNotFoundException {
		in = new Scanner(new File(filename));
		in.useLocale(Locale.US);                 // pour les points de decimales
	}

	public boolean hasNext() {
		return in.hasNext();
	}
	public Point next() {
		return new Point(in.nextDouble(), in.nextDouble());
	}
}

class KCenter {
	int k;
	double tau;
	ArrayList<Point> R;

	KCenter(int k) {
		this.k = k;
		tau = -1;
		R = new ArrayList<Point>();
	}

	void update(Point p) {
		double distmin = Double.MAX_VALUE;
		int    argmin  = -1;
		if (tau<0) {                   // phase d'initialisation
			double d = p.dist(R);
			if (d<distmin) {
				distmin = d;
				argmin  = R.size();
			}
			R.add(p);
			if (R.size()>k) {          // enlever point plus proche
				R.remove(argmin);
				tau = distmin;         // passer a la phase croisiere
			}
		}
		else {                         // phase de croisiere
			if (p.dist(R) > 2*tau) {
				R.add(p);
				while (R.size()>k) {   // doubling tau
					tau *= 2;          // choisir R' maximal
					ArrayList<Point> R1 = new ArrayList<Point>();
					for (Point q: R)
						if (q.dist(R1) >= tau)
							R1.add(q);
					R = R1;
				}
			}
		}
	}

	ArrayList<Point> val() {return R;}

	public static void main(String args[]) throws FileNotFoundException {
		if (args.length!=2) {
			System.err.println("Usage: java KCenter <k> <filename>");
			System.exit(1);
		}
		int k = Integer.parseInt(args[0]);
		String filename = args[1];
		KCenter c = new KCenter(k);
		FluxPoints  f = new FluxPoints(filename);
		while (f.hasNext())                      // nourrir l'algo de clustering avec les points du flux
			c.update(f.next());
		for (Point p: c.val())                   // afficher la solution
			System.out.println(""+p);
	}
}
