import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Scanner; public class canyon_lewin { public static double EPS = 1e-9; public static void main (String[] args) throws FileNotFoundException { Scanner in = new Scanner(System.in); PrintWriter out = new PrintWriter (System.out, true); int N = in.nextInt(), K = in.nextInt(); int[] x = new int[N]; int[] y = new int[N]; for (int i = 0; i < N; i++) { x[i] = in.nextInt(); y[i] = in.nextInt(); } // long start = System.currentTimeMillis(); Polygon p = new Polygon(x,y,N); double[] rect = p.getBounds(); double m = Math.max(rect[3] - rect[1], rect[2] - rect[0]); double lo = m / 3. - EPS, hi = m + EPS; for (int iter = 0; hi - lo > 1e-5 && iter < 50; iter++) { double mid = (lo + hi) / 2.; if (possible(mid, K, p)) hi = mid; else lo = mid; } out.printf("%.2f\n", lo); // System.out.println(System.currentTimeMillis()-start); out.close(); System.exit(0); } public static boolean possible (double sidelen, int left, Polygon p) { if (p.segments.size() == 0) return true; if (left == 0) return false; double[] rect = p.getBounds(); if (rect[3] - rect[1] <= sidelen && rect[2] - rect[0] <= sidelen) return true; if (left == 1) return false; for (int j = 0; j < 2; j++) { for (int i = 0; i < 4; i++) { // cut out upper, then left Polygon[] d = p.cut(p.getBounds()[0] + sidelen); Polygon[] e = d[1].reflect().cut(d[1].getBounds()[1] + sidelen); if (possible(sidelen, left-1, d[0].combine(e[0].reflect()))) return true; p = p.rotate(); } p = p.flip(); } return false; } static class Polygon { public ArrayList segments; public Polygon(int[] x, int[] y, int N) { segments = new ArrayList(); Point[] pts = new Point[N]; for (int i=0; i(); } public double[] getBounds() { double[] ret = new double[4]; ret[0] = 1000000; ret[1] = 1000000; ret[2] = -1000000; ret[3] = -1000000; for (Segment s : segments) { ret[0] = Math.min(ret[0], Math.min(s.a.x, s.b.x)); ret[1] = Math.min(ret[1], Math.min(s.a.y, s.b.y)); ret[2] = Math.max(ret[2], Math.max(s.a.x, s.b.x)); ret[3] = Math.max(ret[3], Math.max(s.a.y, s.b.y)); } return ret; } public Polygon[] cut(double minx) { Polygon[] res = new Polygon[2]; res[0] = new Polygon(); res[1] = new Polygon(); for (Segment cur : segments) { if (cur.a.x <= minx && cur.b.x <= minx) { res[1].segments.add(cur); continue; } if (cur.a.x > minx && cur.b.x > minx) { res[0].segments.add(cur); continue; } // part of it is in forbidden, part is in allowed Point c1 = null; if (cur.a.x > cur.b.x) {Point t = cur.a.copy(); cur.a = cur.b.copy(); cur.b = t;} if (cur.a.x <= minx && cur.b.x > minx) { c1 = cur.b.sub(cur.a).scale((minx - cur.a.x) / (cur.b.x - cur.a.x)).add(cur.a); } if (c1 != null) { res[0].segments.add(new Segment(c1, cur.b)); res[1].segments.add(new Segment(cur.a, c1)); } } return res; } public Polygon combine(Polygon other) { Polygon ret = new Polygon(); ret.segments.addAll(this.segments); ret.segments.addAll(other.segments); return ret; } public Polygon rotate() { Polygon ret = new Polygon(); for (Segment s : segments) { ret.segments.add(new Segment(s.a.rotate(), s.b.rotate())); } return ret; } public Polygon flip() { Polygon ret = new Polygon(); for (Segment s : segments) { ret.segments.add(new Segment(s.a.flip(), s.b.flip())); } return ret; } public Polygon reflect() { Polygon ret = new Polygon(); for (Segment s : segments) { ret.segments.add(new Segment(s.a.reflect(), s.b.reflect())); } return ret; } } static class Segment { public Point a,b; public Segment(Point a, Point b) { this.a = a; this.b = b; } } static class Point { public double x,y; public Point(double x, double y) { this.x = x; this.y = y; } public Point add(Point other) { return new Point(x + other.x, y + other.y); } public Point sub(Point other) { return new Point(x - other.x, y - other.y); } public Point scale(double s) { return new Point(x * s, y * s); } public Point rotate() { return new Point(-y, x); } public Point flip() { return new Point(x, -y); } public Point reflect() { return new Point(y, x); } public Point copy() { return new Point(x,y); } } }