Problem:
Kは多角形のケイ
「
1
番じゃなきゃダメですか？
K
番じゃダメなんでしょうか？」
これがケイ氏の座右の銘である．最近ケイ氏はもっぱら多角形に興味があるようで，目の前に広がる広大な二次元平面上に置かれた
N
個の点を見て，そこから多角形を形成する方法について思いを馳せている．ケイ氏はどうやら，この
N
個の点のうちいくつかの点を選んで自由な順番で繋げることで，選んだ点を頂点とする多角形を構成することにしたようだ．ただし，多角形は以下の条件を満たす必要がある．
単純多角形である．すなわち，3 つ以上の頂点を持ち，連続しない任意の 2 辺が交点を持たない．
選ばれた点以外も含む
N
個すべての点をその内部，または周上に含む．
ケイ氏は己の信念に従って，このような多角形のうち，周長，すなわち全ての辺の長さの和が
K
番目に短い多角形を渇望している．
あなたの仕事は，ケイ氏を手伝うため，条件を満たす多角形のうち，周長の昇順に並べたときに
K
番目となる多角形を求め，その周長を出力するプログラムを書くことだ．ただし，そのような多角形が
K
個以上存在しないこともある．そのようなときにはケイ氏の無念の気持ちを慮りつつ，申し訳ない気持ちを込めながら
-1
と出力する必要がある．
Input
入力は複数のデータセットからなる． 各データセットは次の形式で表される．
N
K
x
1
y
1
...
x
N
y
N
データセットの1行目には二次元平面上の点の数
N
と求める周長の順位
K
が与えられる．
N
,
K
はともに整数であり，
3 ≤ N ≤ 25
,
1 ≤ K ≤ 10
が成り立つ．続く
N
行では各点の二次元平面上の座標が与えられる．
N
行のうち
i
行目には
i
番目の点の
x
座標
x
i
と
y
座標
y
i
がともに整数で与えられ，すべての
1 ≤ i ≤ N
について
-100 ≤ x
i
, y
i
≤ 100
が成り立つ．どの相異なる 3 点を選んでも，その 3 点すべてを通るような直線は存在しないと仮定してよい．また，入力において，周長の昇順に並べたときに
K
番目となる，問題文中に述べた条件を満たす多角形は，存在するならば一意に定まると仮定してよい．
入力の終わりは，2 個のゼロだけからなる行で表される． 全データセットの総数は 50 を超えない．
Output
与えられた点集合からいくつかの点を選び単純多角形を作るとき，構成可能な単純多角形のうち
K
番目に周長が短い多角形の周長を 1 行に出力せよ．そのような多角形が存在しない場合は -1 を出力せよ．結果は
10
-4
以上の誤差を含んではいけない．
Sample Input
5 2
1 1
1 4
2 2
3 1
3 5
3 1
0 2
1 0
-1 0
3 2
0 2
1 0
-1 0
9 10
8 1
9 19
2 10
1 1
4 17
7 13
3 4
6 13
9 21
0 0
Output for the Sample Input
11.812559200041266
6.472135954999580
-1
52.202878812480016

Submitted solutions:

code_snippet: #include <iostream>
#include <iomanip>
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
#include <tuple>
#include <ranges>
namespace ranges = std::ranges;
namespace views = std::views;
// #include "Src/Number/IntegerDivision.hpp"
// #include "Src/Utility/BinarySearch.hpp"
// #include "Src/Sequence/CompressedSequence.hpp"
// #include "Src/Sequence/RunLengthEncoding.hpp"
// #include "Src/Algebra/Group/AdditiveGroup.hpp"
// #include "Src/DataStructure/FenwickTree/FenwickTree.hpp"
// #include "Src/DataStructure/SegmentTree/SegmentTree.hpp"
// #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp"


#include <cstdint>
#include <cstddef>

namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa




namespace zawa {

namespace geometryZ2 {

using Zahlen = i64;

namespace internal {

constexpr i32 positive{1};
constexpr i32 zero{0};
constexpr i32 negative{-1};

} // namespace internal

constexpr i32 Sign(Zahlen value) {
    if (value < 0) return internal::negative;
    if (value > 0) return internal::positive;
    return internal::zero;
}

constexpr bool Positive(Zahlen value) {
    return Sign(value) == internal::positive;
}

constexpr bool Zero(Zahlen value) {
    return Sign(value) == internal::zero;
}

constexpr bool Negative(Zahlen value) {
    return Sign(value) == internal::negative;
}

constexpr Zahlen Abs(Zahlen value) {
    return (value > 0 ? value : -value);
}

constexpr Zahlen Square(Zahlen value) {
    return value * value;
}

} // namespace geometryZ2

} // namespace zawa

#include <limits>

namespace zawa {

namespace geometryZ2 {

class Point {
private:
    Zahlen x_{}, y_{};
    static constexpr i32 origin{0};
    static constexpr i32 firstQuadrant{1};
    static constexpr i32 secondQuadrant{2};
    static constexpr i32 thirdQuadrant{-2};
    static constexpr i32 forthQuadrant{-1};
public:
    /* constructor */
    Point() = default;
    Point(const Point& p) : x_{p.x()}, y_{p.y()} {}
    Point(Zahlen x, Zahlen y) : x_{x}, y_{y} {}

    /* getter setter */
    Zahlen& x() {
        return x_;
    }
    const Zahlen& x() const {
        return x_;
    }
    Zahlen& y() {
        return y_;
    }
    const Zahlen& y() const {
        return y_;
    }

    /* operator */
    Point& operator=(const Point& p) {
        x() = p.x();
        y() = p.y();
        return *this;
    }
    Point& operator+=(const Point& p) {
        x() += p.x();
        y() += p.y();
        return *this;
    }
    friend Point operator+(const Point& p0, const Point& p1) {
        return Point{p0} += p1;
    }
    Point& operator-=(const Point& p) {
        x() -= p.x();
        y() -= p.y();
        return *this;
    }
    friend Point operator-(const Point& p0, const Point& p1) {
        return Point{p0} -= p1;
    }
    Point& operator*=(Zahlen k) {
        x() *= k;
        y() *= k;
        return *this;
    }
    friend Point operator*(const Point& p, Zahlen k) {
        return Point{p} *= k;
    }
    friend Point operator*(Zahlen k, const Point& p) {
        return Point{p} *= k;
    }
    Point& operator/=(Zahlen k) {
        assert(k);
        assert(x() % k == 0);
        assert(y() % k == 0);
        x() /= k;
        y() /= k;
        return *this;
    }
    friend Point operator/(const Point& p, Zahlen k) {
        return Point{p} /= k;
    }
    friend bool operator==(const Point& p0, const Point& p1) {
        return p0.x() == p1.x() and p0.y() == p1.y();
    }
    friend bool operator!=(const Point& p0, const Point& p1) {
        return p0.x() != p1.x() or p0.y() != p1.y();
    }
    friend bool operator<(const Point& p0, const Point& p1) {
        if (p0.x() != p1.x()) return p0.x() < p1.x();
        else return p0.y() < p1.y();
    }
    friend bool operator<=(const Point& p0, const Point& p1) {
        return (p0 < p1) or (p0 == p1);
    }
    friend bool operator>(const Point& p0, const Point& p1) {
        if (p0.x() != p1.x()) return p0.x() > p1.x();
        else return p0.y() > p1.y();
    }
    friend bool operator>=(const Point& p0, const Point& p1) {
        return (p0 > p1) or (p0 == p1);
    }
    friend std::istream& operator>>(std::istream& is, Point& p) {
        is >> p.x() >> p.y();
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const Point& p) {
        os << '(' << p.x() << ',' << p.y() << ')';
        return os;
    }

    /* member function */
    Zahlen normSquare() const {
        return Square(x()) + Square(y());
    }
    bool isNormSquareOver(Zahlen d) const {
        assert(!Negative(d));
        auto [mn, mx]{std::minmax({ Abs(x()), Abs(y()) })};
        if (mx and mx > d / mx) {
            return true;
        }
        long long s1{Square(mn)}, s2{Square(mx)};
        if (s1 > d - s2) {
            return true;
        }
        return false;
    }
    bool isNormSquareOverflow() const {
        return isNormSquareOver(std::numeric_limits<Zahlen>::max());
    }

    i32 area() const {
        if (x_ == 0 and y_ == 0) return origin;
        if (x_ <= 0 and y_ < 0) return thirdQuadrant;
        if (x_ > 0 and y_ <= 0) return forthQuadrant;
        if (x_ >= 0 and y_ > 0) return firstQuadrant;
        return secondQuadrant;
    }

    /* static member */
    static bool ArgComp(const Point& p0, const Point& p1) {
        if (p0.area() != p1.area()) return p0.area() < p1.area();
        Zahlen cross{Cross(p0, p1)};
        return (!Zero(cross) ? Positive(cross) : p0.normSquare() < p1.normSquare());
    }

    /* friend function */
    friend Zahlen Dot(const Point& p0, const Point& p1) {
        return p0.x() * p1.x() + p0.y() * p1.y();
    }
    friend Zahlen Cross(const Point& p0, const Point& p1) {
        return p0.x() * p1.y() - p0.y() * p1.x();
    }
};
using Vector = Point;

} // namespace geometryZ2

} // namespace zawa


namespace zawa {

namespace geometryZ2 {

enum RELATION {
    // p0 -> p1 -> p2の順で直線上に並んでいる
    ONLINE_FRONT        = -2,
    // (p1 - p0) -> (p2 - p0)が時計回りになっている
    CLOCKWISE           = -1,
    // p0 -> p2 -> p1の順で直線上に並んでいる
    ON_SEGMENT          =  0,
    // (p1 - p0) -> (p2 - p0)が反時計回りになっている
    COUNTER_CLOCKWISE   = +1,
    // p2 -> p0 -> p1、またはp1 -> p0 -> p2の順で直線上に並んでいる
    ONLINE_BACK         = +2
};

RELATION Relation(const Point& p0, const Point& p1, const Point& p2) {
    Point a{p1 - p0}, b{p2 - p0};
    if (Positive(Cross(a, b))) return COUNTER_CLOCKWISE;
    if (Negative(Cross(a, b))) return CLOCKWISE;
    if (Negative(Dot(a, b))) return ONLINE_BACK;
    if (a.normSquare() < b.normSquare()) return ONLINE_FRONT;
    return ON_SEGMENT;
};

} // namespace geometryZ2

} // namespace zawa

#include <iterator>
#include <type_traits>

namespace zawa {

namespace geometryZ2 {

class Polygon {
private:
    std::vector<Point> data_;
public:
    usize size() const {
        return data_.size(); 
    }

    /* constructor */
    Polygon() = default;
    Polygon(const Polygon& polygon) : data_{polygon.data_} {}
    Polygon(const std::vector<Point>& data) : data_{data} {}
    Polygon(usize n) : data_{n} {
        assert(n >= static_cast<usize>(3));
    }

    /* operator */
    Polygon& operator=(const Polygon& polygon) {
        data_ = polygon.data_;
        return *this;
    }
    Point& operator[](usize i) {
        assert(i < size());
        return data_[i];
    }
    const Point& operator[](usize i) const {
        assert(i < size());
        return data_[i];
    }
    friend std::istream& operator>>(std::istream& is, Polygon& polygon) {
        for (size_t i{} ; i < polygon.size() ; i++) {
            is >> polygon[i];
        }
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const Polygon& polygon) {
        for (usize i{} ; i < polygon.size() ; i++) {
            std::cout << polygon[i] << (i + 1 == polygon.size() ? "" : " ");
        }
        return os;
    }

    /* member function */
    void reserve(usize n) {
        data_.reserve(n);
    }
    void pushBack(const Point& p) {
        data_.push_back(p);
    }
    void emplaceBack(Zahlen x, Zahlen y) {
        data_.emplace_back(x, y);
    }
    template <class RandomAccessIterator>
    void insert(usize n, RandomAccessIterator first, RandomAccessIterator last) {
        assert(n <= size());
        data_.insert(std::next(data_.begin(), n), first, last);
    }
    void orderRotate(usize i) {
        assert(i < size());
        std::rotate(data_.begin(), data_.begin() + i, data_.end());
    }
    template <class F>
    void normalForm(const F& func) {
        auto index{std::distance(data_.begin(), std::min_element(data_.begin(), data_.end(), func))};
        orderRotate(index);
    }
    void normalForm() {
        auto index{std::distance(data_.begin(), std::min_element(data_.begin(), data_.end()))};
        orderRotate(index);
    }
    template <class F>
    Polygon normalFormed(const F& func = [](const Point& a, const Point& b) -> bool { return a < b; }) const {
        Polygon res{*this};
        res.normalForm(func);
        return res;
    }
    Polygon normalFormed() {
        Polygon res{*this};
        res.normalForm();
        return res;
    }
    bool isConvex() const {
        assert(size() >= static_cast<usize>(3));
        for (usize i{} ; i < size() ; i++) {
            if (Relation(data_[i], data_[i+1==size()?0:i+1], data_[i+2>=size()?i+2-size():i+2])
                    == CLOCKWISE) {
                return false;
            }
        }
        return true;
    }
    Zahlen areaTwice() const {
        assert(size() >= static_cast<usize>(3));
        Zahlen res{};
        for (usize i{1} ; i < size() ; i++) {
            res += Cross(data_[i] - data_[0], data_[i+1==size()?0:i+1] - data_[0]);
        }
        return res;
    }
    Polygon subtriangle(usize i, usize j, usize k) const {
        assert(i < size());
        assert(j < size());
        assert(k < size());
        return Polygon{std::vector<Point>{ data_[i], data_[j], data_[k] }};
    }
};

}

} // namespace zawa




namespace zawa {

namespace geometryZ2 {

using PointCloud = std::vector<Point>;

void ArgSort(PointCloud& p) {
    std::sort(p.begin(), p.end(), Point::ArgComp);
}

} // namespace geometryZ2 

} // namespace zawa


namespace zawa {

namespace geometryZ2 {

template <bool strictly>
Polygon ConvexHull(const PointCloud& p) {
    PointCloud cp{p};
    std::sort(cp.begin(), cp.end());
    cp.erase(std::unique(cp.begin(), cp.end()), cp.end());
    if (cp.size() <= 2u) {
        return Polygon{cp};
    }
    PointCloud lower;
    lower.reserve(p.size());
    for (auto it{cp.begin()} ; it != cp.end() ; it++) {
        lower.push_back(*it);
        while (lower.size() >= 3u) {
            if (Relation(lower[lower.size() - 3], lower[lower.size() - 2], lower[lower.size() - 1]) == COUNTER_CLOCKWISE) {
                break;
            }
            if constexpr (!strictly) {
                if (Relation(lower[lower.size() - 3], lower[lower.size() - 2], lower[lower.size() - 1]) == ONLINE_FRONT) {
                    break;
                }
            }
            std::swap(lower[lower.size() - 2], lower[lower.size() - 1]);
            lower.pop_back();
        }
    }
    PointCloud upper;
    upper.reserve(p.size());
    for (auto it{cp.rbegin()} ; it != cp.rend() ; it++) {
        upper.push_back(*it);
        while (upper.size() >= 3u) {
            if (Relation(upper[upper.size() - 3], upper[upper.size() - 2], upper[upper.size() - 1]) == COUNTER_CLOCKWISE) {
                break;
            }
            if constexpr (!strictly) {
                if (Relation(upper[upper.size() - 3], upper[upper.size() - 2], upper[upper.size() - 1]) == ONLINE_FRONT) {
                    break;
                }
            }
            std::swap(upper[upper.size() - 2], upper[upper.size() - 1]);
            upper.pop_back();
        }
    }

    Polygon res;
    res.reserve(lower.size() + upper.size() - 2);
    res.insert(res.size(), lower.begin(), lower.end());
    res.insert(res.size(), std::next(upper.begin()), std::prev(upper.end()));
    return res;
}

} // namespace geometryZ2

} // namespace zawa


namespace zawa {

namespace geometryZ2 {

class Segment {
private:
    Point p0_{}, p1_{};
public:
    /* constructor */
    Segment() = default;
    Segment(const Segment& s) : p0_{s.p0_}, p1_{s.p1_} {}
    Segment(const Point& p0, const Point& p1) : p0_{p0}, p1_{p1} {}

    /* getter, setter */ 
    const Point& p0() const {
        return p0_;
    }
    Point& p0() {
        return p0_;
    }
    const Point& p1() const {
        return p1_;
    }
    Point& p1() {
        return p1_;
    }

    /* operator */
    Segment& operator=(const Segment& s) {
        p0_ = s.p0();
        p1_ = s.p1();
        return *this;
    }
    friend bool operator==(const Segment& s0, const Segment& s1) {
        return (s0.p0() == s1.p0() and s0.p1() == s1.p1())
            or (s0.p1() == s1.p1() and s0.p1() == s1.p0());
    }
    friend bool operator!=(const Segment& s0, const Segment& s1) {
        return !(s0 == s1);
    }

    /* member function */
    bool valid() const {
        return p0_ != p1_;
    }
    bool straddle(const Segment& s) const {
        return Relation(p0_, p1_, s.p0()) * Relation(p0_, p1_, s.p1()) <= 0;
    }
};

} // namespace geometryZ2

} // namespace zawa


namespace zawa {

namespace geometryZ2 {

bool Intersect(const Segment& s0, const Segment& s1) {
    assert(s0.valid());
    assert(s1.valid());
    return s0.straddle(s1) and s1.straddle(s0);
}

} // namespace geometryZ2

} // namespace zawa


namespace zawa {

namespace geometryZ2 {

Zahlen DistanceSquare(const Point& p0, const Point& p1) {
    return Vector{p1 - p0}.normSquare();
}

} // namespace geometryZ2

} // namespace zawa
using namespace zawa;
using namespace geometryZ2;
// #include "atcoder/modint"
// using mint = atcoder::modint998244353;
#include <set>
#include <queue>
#include <cmath>
#include <random>
int N, K;
PointCloud P;
std::vector<int> normalized(std::vector<int> A) {
    assert(std::ssize(A) >= 3);
    const int it = ranges::min_element(A) - A.begin();
    ranges::rotate(A, A.begin() + it);
    if (A[1] > A[A.size() - 1]) {
        ranges::reverse(A.begin() + 1, A.end());
    }
    return A;
}
bool is_simple(const std::vector<int>& A) {
    assert(std::ssize(A) >= 3);
    for (int i = 0 ; i < std::ssize(A) ; i++) {
        for (int j = i + 2 ; j < std::ssize(A) ; j++) {
            if (i == 0 and j + 1 == std::ssize(A)) continue;
            const Segment s{P[A[i]], P[A[(i + 1)%A.size()]]};
            const Segment t{P[A[j]], P[A[(j + 1)%A.size()]]};
            if (Intersect(s, t)) return false;
        }
    }
    return true;
}
long double length(const std::vector<int>& A) {
    assert(std::ssize(A) >= 3);
    long double res = 0; 
    for (int i = 0 ; i < std::ssize(A) ; i++) {
        res += sqrtl(DistanceSquare(P[A[i]], P[A[(i+1)%A.size()]]));
    }
    return res;
}
std::mt19937 mt{std::random_device{}()};
bool inside(const Polygon& poly, const Point& p) {
    const Segment seg = [&]() -> Segment {
        while (true) {
            const Point cond(mt() % (Zahlen)2000000000LL, mt() % (Zahlen)2000000000LL);
            bool ok = true;
            for (int i = 0 ; ok and i < std::ssize(poly) ; i++) {
                ok &= Relation(p, cond, poly[i]) != RELATION::ON_SEGMENT;
            }
            if (ok) return {p, cond};
        }
        return {p, p};
    }();
    int cnt = 0;
    for (int i = 0 ; i < std::ssize(poly) ; i++) {
        if (Intersect(seg, Segment{poly[i], poly[(i+1)%poly.size()]})) cnt++;
    }
    return cnt & 1;
}
bool contains_all(const std::vector<int>& A) {
    std::vector<bool> used(N);
    for (int i : A) used[i] = true;
    Polygon poly(A.size());
    for (int i = 0 ; i < std::ssize(A) ; i++) poly[i] = P[A[i]];
    for (int i = 0 ; i < N ; i++) if (!used[i] and !inside(poly, P[i])) {
        return false;
    }
    return true;
}
std::optional<long double> solve() {
    using qt = std::pair<long double, std::vector<int>>;
    std::set<std::vector<int>> set;
    std::priority_queue<qt, std::vector<qt>, std::greater<qt>> que;
    {
        const auto ch = ConvexHull<true>(P);
        std::vector<int> poly(ch.size());
        for (int i = 0 ; i < std::ssize(ch) ; i++) {
            for (int j = 0 ; j < N ; j++) if (ch[i] == P[j]) {
                poly[i] = j;
                break;
            }
        }
        assert(is_simple(poly));
        poly = normalized(poly);
        set.insert(poly);
        que.push({length(poly), poly});
    }
    for (int t = 1 ; que.size() and t <= K ; t++) {
        auto [len, poly] = que.top();
        que.pop();
        if (t == K) return len;
        std::vector<bool> used(N);
        for (int p : poly) used[p] = true;
        for (int i = 0 ; i < N ; i++) if (!used[i]) {
            for (int j = 0 ; j <= std::ssize(poly) ; j++) {
                std::vector<int> npoly = poly;
                npoly.insert(npoly.begin() + j, i);
                if (!is_simple(npoly)) continue;
                if (!contains_all(npoly)) continue;
                npoly = normalized(npoly);
                if (set.contains(npoly)) continue;
                set.insert(npoly);
                que.push({length(npoly), npoly});
            }
        }
    }
    return std::nullopt;
}
int main() {
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(6);
    while (true) {
        std::cin >> N >> K;
        if (N == 0 and K == 0) break;
        P = PointCloud(N);
        for (int i = 0 ; i < N ; i++) std::cin >> P[i];
        const auto ans = solve();
        if (ans) std::cout << ans.value() << '\n';
        else std::cout << -1 << '\n';
    }
}
accuracy: 1
time_ms: 30
memory_kb: 4096
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;

#include <atcoder/all>
using namespace atcoder;

using ll = long long;
using mint = modint998244353;

namespace geometry {

using Real = long double;
constexpr Real eps = 1e-7;
constexpr Real PI = acosl(-1);
constexpr Real INF_REAL = numeric_limits<Real>::max();

bool is_same(Real a, Real b) {
    return abs(a - b) < eps;
}

int sgn(Real a) {
    return is_same(a, 0) ? 0 : a > 0 ? 1 : -1;
}

struct Point {
    Real x, y;
    constexpr Point() : Point(0, 0) {}
    constexpr Point(Real _x, Real _y) : x(_x), y(_y) {}
    constexpr Point(const pair<Real, Real> &p) : x(p.first), y(p.second) {}
    Point &operator+=(const Point &p) {
        x += p.x;
        y += p.y;
        return *this;
    }
    Point &operator-=(const Point &p) {
        x -= p.x;
        y -= p.y;
        return *this;
    }
    Point &operator*=(const Real &r) {
        x *= r;
        y *= r;
        return *this;
    }
    Point &operator/=(const Real &r) {
        assert(!is_same(r, 0));
        x /= r;
        y /= r;
        return *this;
    }
    Point operator+(const Point &p) const { return Point(*this) += p; }
    Point operator-(const Point &p) const { return Point(*this) -= p; }
    Point operator*(const Real &r) const { return Point(*this) *= r; }
    Point operator/(const Real &r) const { return Point(*this) /= r; }
    Point operator-() const { return Point() - *this; }
    bool operator==(const Point &p) const {
        return is_same(x, p.x) && is_same(y, p.y);
    }
    bool operator!=(const Point &p) const {
        return !is_same(x, p.x) || !is_same(y, p.y);
    }
    Point rotate(Real rad) const {
        Real c = cosl(rad), s = sinl(rad);
        Real tx = x * c - y * s;
        Real ty = x * s + y * c;
        return Point(tx, ty);
    }
    Real Re() const { return x; }
    Real Im() const { return y; }
    Real norm() const { return x * x + y * y; }
    Real abs() const { return sqrtl(norm()); }
    Real arg() const { return atan2l(y, x); }
    friend Point operator*(Real r, const Point &p) {
        return p * r;
    }
    friend Point operator/(Real r, const Point &p) {
        return p / r;
    }
};

Real Re(const Point &p) { return p.Re(); }
Real Im(const Point &p) { return p.Im(); }
Real dot(const Point &p, const Point &q) {
    return p.x * q.x + p.y * q.y;
}
Real cross(const Point &p, const Point &q) {
    return p.x * q.y - p.y * q.x;
}
Real norm(const Point &p) {
    return p.norm();
}
Real abs(const Point &p) {
    return p.abs();
}
Real arg(const Point &p) {
    return p.arg();
}

constexpr Point INF_POINT = Point(INF_REAL, INF_REAL);

// a を基準にした b と c の位置関係
int ccw(const Point &a, const Point &b, const Point &c) {
    Point p = b - a, q = c - a;
    if (cross(p, q) > eps) return 1; // a, b, c の順で反時計回り
    if (cross(p, q) < -eps) return -1; // a, b, c の順で時計回り
    if (min(norm(p), norm(q)) < eps * eps) return 0; // a = c or b = c
    if (dot(p, q) < eps) return 2; // c, a, b の順で一直線
    if (norm(p) < norm(q)) return -2; // a, b, c の順で一直線
    return 0; // a, c, b の順で一直線
}

struct Line {
    // Line : ax + by = c
    Real a, b, c;
    constexpr Line() = default;
    constexpr Line(Real _a, Real _b, Real _c) : a(_a), b(_b), c(_c) {}
    constexpr Line(const Point &p, const Point &q) : a(q.y - p.y), b(p.x - q.x), c(p.x * q.y - p.y * q.x) {}
    constexpr Line(Real _a, const Point &p) : a(_a), b(-1), c(_a * p.x - p.y) {}
    bool online(const Point &p) const {
        return is_same(a * p.x + b * p.y, c);
    }
    Real get_x(Real y) const {
        if (is_same(a, 0)) return INF_REAL;
        return (c - b * y) / a;
    }
    Real get_y(Real x) const {
        if (is_same(b, 0)) return INF_REAL;
        return (c - a * x) / b;
    }
    Line perpendicular(const Point &p) const {
        if (is_same(a, 0)) return Line(1, 0, p.x);
        if (is_same(0, b)) return Line(0, 1, p.y);
        return Line(b / a, p);
    }
    Point crossppoint(const Line &l) const {
        if (is_same(a * l.b, l.a * b)) return INF_POINT;
        Real d = a * l.b - l.a * b;
        return Point(l.b * c - b * l.c, l.c * a - c * l.a) / d;
    }
    Point projection(const Point &p) const {
        return crossppoint(perpendicular(p));
    }
    Point reflection(const Point &p) const {
        Point q = projection(p);
        return 2 * q - p;
    }
    bool is_orthogonal(const Line &l) const {
        return is_same(a * l.a + b * l.b, 0);
    }
    bool is_parallel(const Line &l) const {
        return is_same(a * l.b, l.a * b);
    }
    Real dist(const Point &p) const {
        Point q = projection(p);
        return abs(p - q);
    }
};

bool is_orthogonal(const Line &l1, const Line &l2) {
    return l1.is_orthogonal(l2);
}
bool is_parallel(const Line &l1, const Line &l2) {
    return l1.is_parallel(l2);
}
Point crosspoint(const Line &l1, const Line &l2) {
    return l1.crossppoint(l2);
}

struct Polygon : vector<Point> {
    using vector<Point>::vector;
    Polygon(const vector<Point>& pts) : vector<Point>(pts) {}
    int contain(const Point &p) const {
        int n = this->size();
        bool in = false;
        for (int i = 0; i < n; i++) {
            Point a = (*this)[i] - p;
            Point b = (*this)[i == n - 1 ? 0 : i + 1] - p;
            // need std::
            if (Im(a) > Im(b)) std::swap(a, b);
            if (sgn(Im(a)) <= 0 && 0 < sgn(Im(b)) && sgn(cross(a, b)) < 0) in = !in;
            if (is_same(cross(a, b), 0) && sgn(dot(a, b)) <= 0) return 1;
        }
        return in ? 2 : 0;
    }
    Real area() const {
        int n = this->size();
        Real S = 0;
        for (int i = 0; i < n; i++) {
            Point a = (*this)[i];
            Point b = (*this)[i == n - 1 ? 0 : i + 1];
            S += cross(a, b);
        }
        return S * 0.5;
    }
    bool is_convex() const {
        int n = this->size();
        if (n <= 2) return false;
        for (int i = 0, j = 1, k = 2; i < n; i++, j++, k++) {
            if (j == n) j = 0;
            if (k == n) k = 0;
            if (ccw((*this)[i], (*this)[j], (*this)[k]) == -1) return false;
        }
        return true;
    }
    void relabeling() {
        Real x_min = INF_REAL, y_min = INF_REAL;
        int idx = 0, n = this->size();
        for (int i = 0; i < n; i++) {
            Real x = (*this)[i].x, y = (*this)[i].y;
            if (y < y_min || (is_same(y, y_min) && x < x_min)) {
                x_min = x;
                y_min = y;
                idx = i;
            }
        }
        Polygon tmp(n);
        int pre = (idx + n - 1) % n, nxt = (idx + 1) % n;
        if (ccw((*this)[idx], (*this)[pre], (*this)[nxt]) == -1) {
            for (int i = 0; i < n; i++) {
                tmp[i] = (*this)[(idx + i) % n];
            }
        } else {
            for (int i = 0; i < n; i++) {
                tmp[i] = (*this)[(idx + n - i) % n];
            }
        }
        *this = tmp;
    }
};

Polygon convex_hull(vector<Point> pts, bool exclude_collinear = true) {
    int n = pts.size(), k = 0;
    sort(pts.begin(), pts.end(), [](const Point &p, const Point &q){
        return is_same(Re(p), Re(q)) ? Im(p) < Im(q) : Re(p) < Re(q);
    });
    vector<Point> ch(2 * n);
    for (int i = 0; i < n; ch[k++] = pts[i++]) {
        while ((k >= 2 && [&] {
            Real d = cross(ch[k - 1] - ch[k - 2], pts[i] - ch[k - 1]);
            return exclude_collinear ? d < eps : d < -eps;
        }()) || (k >= 1 && ch[k - 1] == pts[i])) k--;
    }
    for (int i = n - 2, j = k + 1; i >= 0; ch[k++] = pts[i--]) {
        while ((k >= j && k >= 2 && [&] {
            Real d = cross(ch[k - 1] - ch[k - 2], pts[i] - ch[k - 1]);
            return exclude_collinear ? d < eps : d < -eps;
        }()) || (k >= 1 && ch[k - 1] == pts[i])) k--;
    }
    ch.resize(k - 1);
    return Polygon(ch);
}

struct Segment {
    Line l;
    Point p, q;
    Segment() = default;
    Segment(const Point &_p, const Point &_q) : l(_p, _q), p(_p), q(_q) {}
    bool cross(const Segment &s) const {
        bool f1 = ccw(p, q, s.p) * ccw(p, q, s.q) <= 0;
        bool f2 = ccw(s.p, s.q, p) * ccw(s.p, s.q, q) <= 0;
        return f1 && f2;
    }
    Point crosspoint(const Segment &s) const {
        if (cross(s)) return l.crossppoint(s.l);
        return INF_POINT;
    }
    Real dist(const Point &r) const {
        if (dot(q - p, r - p) < eps) return (r - p).abs();
        if (dot(p - q, r - q) < eps) return (r - q).abs();
        return l.dist(r);
    }
    Real dist(const Segment &s) const {
        if (cross(s)) return 0;
        Real res = INF_REAL;
        res = min(res, dist(s.p));
        res = min(res, dist(s.q));
        res = min(res, s.dist(p));
        res = min(res, s.dist(q));
        return res;
    }
};

bool cross(const Segment &s, const Segment &t) {
    return s.cross(t);
}

Point crosspoint(const Segment &s, const Segment &t) {
    return s.crosspoint(t);
}

Real dist(const Segment &s, const Segment &t) {
    return s.dist(t);
}

} // namespace geometry

using namespace geometry;

bool is_simple(Polygon P) {
    int N = P.size();
    vector<Segment> segs;
    for(int i = 0; i < N; i++) {
        Point p = P[i];
        Point q = P[(i + 1) % N];
        Segment seg(p, q);
        segs.push_back(seg);
    }
    for(int i = 0; i < N - 1; i++) {
        for(int j = i + 2; j < N; j++) {
            if(i == 0 && j == N - 1) continue;
            if(segs[i].cross(segs[j])) return false;
        }
    }
    return true;
}

Real outer_length(Polygon P) {
    Real ret = 0;
    int N = P.size();
    for(int i = 0; i < N; i++) {
        Point p = P[i];
        Point q = P[(i + 1) % N];
        ret += (p - q).abs();
    }
    return ret;
}

bool solve() {
    int N, K;
    cin >> N >> K;
    if(N == 0) return false;
    Polygon P(N);
    for(int i = 0; i < N; i++) {
        Real x, y;
        cin >> x >> y;
        Point p(x, y);
        P[i] = p;
    }

    Polygon hull = convex_hull(P);
    vector<int> ids_hull;
    for(Point p : hull) {
        for(int i = 0; i < N; i++) {
            if(p == P[i]) {
                ids_hull.push_back(i);
                // cout << p.x << " " << p.y << endl;
            }
        }
    }

    // cout << is_simple(hull) << endl;
    // return false;
    // cout << N << " " << K << " " << hull.size() << endl;
    // cout << outer_length(hull) << endl;
    
    using PAIR = pair<Real, vector<int>>;
    priority_queue<PAIR, vector<PAIR>, greater<PAIR>> que;
    set<vector<int>> used;
    que.push(PAIR{outer_length(hull), ids_hull});
    for(int t = 1; t <= K;) {
        // cout << que.size() << endl;
        if(que.empty()) {
            cout << -1 << endl;
            break;
        }
        auto [len, ids] = que.top();
        que.pop();
        if(used.count(ids)) {
            continue;
        }if(t == K) {
            cout << fixed << setprecision(7) << len << endl;
            break;
        }
        // cout << "#";
        // for(int id : ids) cout << " " << id + 1;
        // cout << endl;
        used.insert(ids);
        set<int> st(ids.begin(), ids.end());
        for(int i = 0; i < N; i++) {
            if(st.count(i)) continue;
            // cout << i << endl;
            for(int k = 1; k <= ids.size(); k++) {
                // cout << k << endl;
                ids.insert(ids.begin() + k, i);
                // cout << "#";
                // for(int id : ids) cout << " " << id + 1; cout << endl;
                Polygon poly;
                for(int id : ids) poly.push_back(P[id]);
                // cout << outer_length(poly) << " " << is_simple(poly) << endl;
                bool ok = true;
                for(int j = 0; j < N; j++) {
                    if(j == k || st.count(j)) continue;
                    if(poly.contain(P[j]) == 0) ok = false;
                }
                if(ok && is_simple(poly) && !used.count(ids)) {
                    que.push(PAIR{outer_length(poly), ids});
                }
                ids.erase(ids.begin() + k);
            }
        }
        t++;
    }
    return true;
}

int main() {
    while(solve());
}
accuracy: 0.5
time_ms: 30
memory_kb: 4096
final_rank: 20

code_snippet: // AOJ #2950 K is Key of Takakkey
// 2025.3.11

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double EPS = 1e-9;

struct P { double x, y; };

int N, K;
vector<P> pts;
vector<bool> isHull;

double dist(const P &a, const P &b) {
    double dx = a.x - b.x, dy = a.y - b.y;
    return sqrt(dx*dx + dy*dy);
}

double cross(const P &a, const P &b, const P &c) {
    return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}

vector<int> getHull() {
    vector<int> idx(N);
    for(int i = 0; i < N; i++) idx[i] = i;
    sort(idx.begin(), idx.end(), [&](int i, int j){
        if(fabs(pts[i].x - pts[j].x) > EPS) return pts[i].x < pts[j].x;
        return pts[i].y < pts[j].y;
    });
    vector<int> up, dn;
    for (int i : idx) {
        while(up.size()>=2 && cross(pts[up[up.size()-2]], pts[up.back()], pts[i]) <= EPS) up.pop_back();
        up.push_back(i);
    }
    for (int i = idx.size()-1; i>=0; i--) {
        int j = idx[i];
        while(dn.size()>=2 && cross(pts[dn[dn.size()-2]], pts[dn.back()], pts[j]) <= EPS) dn.pop_back();
        dn.push_back(j);
    }
    dn.pop_back(); up.pop_back();
    vector<int> h = up;
    h.insert(h.end(), dn.begin(), dn.end());
    return h;
}

bool onSeg(const P &p, const P &q, const P &r) {
    return q.x <= max(p.x, r.x)+EPS && q.x+EPS >= min(p.x, r.x) &&
           q.y <= max(p.y, r.y)+EPS && q.y+EPS >= min(p.y, r.y);
}

bool segInt(const P &a, const P &b, const P &c, const P &d) {
    double o1 = cross(a,b,c), o2 = cross(a,b,d);
    double o3 = cross(c,d,a), o4 = cross(c,d,b);
    if(o1*o2 < -EPS && o3*o4 < -EPS) return true;
    if(fabs(o1) < EPS && onSeg(a,c,b)) return true;
    if(fabs(o2) < EPS && onSeg(a,d,b)) return true;
    if(fabs(o3) < EPS && onSeg(c,a,d)) return true;
    if(fabs(o4) < EPS && onSeg(c,b,d)) return true;
    return false;
}

bool simple(const vector<int> &poly) {
    int m = poly.size();
    for (int i = 0; i < m; i++){
        int i2 = (i+1)%m;
        for (int j = i+1; j < m; j++){
            int j2 = (j+1)%m;
            if(i==j || i2==j || i==(j2)) continue;
            if(segInt(pts[poly[i]], pts[poly[i2]], pts[poly[j]], pts[poly[j2]])) return false;
        }
    }
    return true;
}

bool inPoly(const P &p, const vector<int> &poly) {
    bool in = false;
    int m = poly.size();
    for (int i = 0, j = m-1; i < m; j = i++) {
        const P &pi = pts[poly[i]], &pj = pts[poly[j]];
        double cp = cross(pj, pi, p);
        if(fabs(cp) < EPS && p.x <= max(pj.x,pi.x)+EPS && p.x+EPS >= min(pj.x,pi.x) &&
           p.y <= max(pj.y,pi.y)+EPS && p.y+EPS >= min(pj.y,pi.y)) return true;
        bool cond = ((pi.y > p.y) != (pj.y > p.y)) &&
                      (p.x < (pj.x-pi.x)*(p.y-pi.y)/(pj.y-pi.y+EPS)+pi.x);
        if(cond) in = !in;
    }
    return in;
}

bool containAll(const vector<int> &poly) {
    for (int i = 0; i < N; i++){
        if(!inPoly(pts[i], poly)) return false;
    }
    return true;
}

double perim(const vector<int> &poly) {
    double s = 0;
    int m = poly.size();
    for (int i = 0; i < m; i++) s += dist(pts[poly[i]], pts[poly[(i+1)%m]]);
    return s;
}

string norm(const vector<int> &poly) {
    int m = poly.size();
    int pos = 0;
    for (int i = 1; i < m; i++) if(poly[i] < poly[pos]) pos = i;
    string s;
    for (int i = 0; i < m; i++){
        int idx = poly[(pos+i)%m];
        s += to_string(idx) + ",";
    }
    return s;
}

struct Cand {
    double p;
    vector<int> poly;
    int mask;
};

struct CandComp {
    bool operator()(const Cand &a, const Cand &b) {
        return a.p > b.p;
    }
};

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    while(cin >> N >> K) {
        if(N==0 && K==0) break;
        pts.resize(N);
        for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;

        vector<int> h = getHull();
        isHull.assign(N, false);
        for (int i : h) isHull[i] = true;

        int m = h.size();
        int mask = 0;
        for (int i : h) mask |= (1 << i);
        double p0 = perim(h);
        Cand c0 { p0, h, mask };

        priority_queue<Cand, vector<Cand>, CandComp> pq;
        pq.push(c0);
        unordered_set<string> vis;
        vis.insert(norm(h));

        int cnt = 0;
        double ans = -1;
        while(!pq.empty()){
            Cand cur = pq.top(); pq.pop();
            cnt++;
            if(cnt == K) {
                ans = cur.p;
                break;
            }
            int sz = cur.poly.size();
            for (int i = 0; i < sz; i++){
                int j = (i+1) % sz;
                for (int v = 0; v < N; v++){
                    if(cur.mask & (1<<v)) continue;
                    if(isHull[v]) continue;
                    vector<int> np = cur.poly;
                    np.insert(np.begin()+j, v);
                    int nmask = cur.mask | (1 << v);
                    if(!simple(np)) continue;
                    if(!containAll(np)) continue;
                    double npd = perim(np);
                    string key = norm(np);
                    if(vis.count(key)) continue;
                    vis.insert(key);
                    pq.push({npd, np, nmask});
                }
            }
        }
        if(ans < 0) cout << -1 << endl;
        else cout << fixed << setprecision(15) << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3776
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

using T = double;
const T eps = 1e-8;
using Point = complex<T>;
using Poly = vector<Point>;
#define X real()
#define Y imag()
template <typename T> inline bool eq(const T &a, const T &b) {
    return fabs(a - b) < eps;
}
bool cmp(const Point &a, const Point &b) {
    auto sub = [&](Point a) {
        return (a.Y < 0 ? -1 : (a.Y == 0 && a.X >= 0 ? 0 : 1));
    };
    if (sub(a) != sub(b))
        return sub(a) < sub(b);
    return a.Y * b.X < a.X * b.Y;
}
struct Line {
    Point a, b, dir;
    Line() {}
    Line(Point _a, Point _b) : a(_a), b(_b), dir(b - a) {}
    Line(T A, T B, T C) {
        if (eq(A, .0)) {
            a = Point(0, C / B), b = Point(1 / C / B);
        } else if (eq(B, .0)) {
            a = Point(C / A, 0), b = Point(C / A, 1);
        } else {
            a = Point(0, C / B), b = Point(C / A, 0);
        }
    }
};
struct Segment : Line {
    Segment() {}
    Segment(Point _a, Point _b) : Line(_a, _b) {}
};
struct Circle {
    Point p;
    T r;
    Circle() {}
    Circle(Point _p, T _r) : p(_p), r(_r) {}
};

istream &operator>>(istream &is, Point &p) {
    T x, y;
    is >> x >> y;
    p = Point(x, y);
    return is;
}
ostream &operator<<(ostream &os, Point &p) {
    os << fixed << setprecision(12) << p.X << ' ' << p.Y;
    return os;
}
Point unit(const Point &a) {
    return a / abs(a);
}
T dot(const Point &a, const Point &b) {
    return a.X * b.X + a.Y * b.Y;
}
T cross(const Point &a, const Point &b) {
    return a.X * b.Y - a.Y * b.X;
}
Point rot(const Point &a, const T &theta) {
    return Point(cos(theta) * a.X - sin(theta) * a.Y,
                 sin(theta) * a.X + cos(theta) * a.Y);
}
Point rot90(const Point &a) {
    return Point(-a.Y, a.X);
}
T arg(const Point &a, const Point &b, const Point &c) {
    double ret = acos(dot(a - b, c - b) / abs(a - b) / abs(c - b));
    if (cross(a - b, c - b) < 0)
        ret = -ret;
    return ret;
}

Point Projection(const Line &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Projection(const Segment &l, const Point &p) {
    T t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + (l.a - l.b) * t;
}
Point Reflection(const Line &l, const Point &p) {
    return p + (Projection(l, p) - p) * 2.;
}
int ccw(const Point &a, Point b, Point c) {
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // ccw

    if (cross(b, c) < -eps)
        return -1; // cw

    if (dot(b, c) < 0)
        return 2; // c,a,b

    if (norm(b) < norm(c))
        return -2; // a,b,c

    return 0;      // a,c,b

}
bool isOrthogonal(const Line &a, const Line &b) {
    return eq(dot(a.b - a.a, b.b - b.a), .0);
}
bool isParallel(const Line &a, const Line &b) {
    return eq(cross(a.b - a.a, b.b - b.a), .0);
}
bool isIntersect(const Segment &a, const Segment &b) {
    return ccw(a.a, a.b, b.a) * ccw(a.a, a.b, b.b) <= 0 and
           ccw(b.a, b.b, a.a) * ccw(b.a, b.b, a.b) <= 0;
}
int isIntersect(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d > a.r + b.r + eps)
        return 4;
    if (eq(d, a.r + b.r))
        return 3;
    if (eq(d, abs(a.r - b.r)))
        return 1;
    if (d < abs(a.r - b.r) - eps)
        return 0;
    return 2;
}
T Dist(const Line &a, const Point &b) {
    Point c = Projection(a, b);
    return abs(c - b);
}
T Dist(const Segment &a, const Point &b) {
    if (dot(a.b - a.a, b - a.a) < eps)
        return abs(b - a.a);
    if (dot(a.a - a.b, b - a.b) < eps)
        return abs(b - a.b);
    return abs(cross(a.b - a.a, b - a.a)) / abs(a.b - a.a);
}
T Dist(const Segment &a, const Segment &b) {
    if (isIntersect(a, b))
        return .0;
    T res = min({Dist(a, b.a), Dist(a, b.b), Dist(b, a.a), Dist(b, a.b)});
    return res;
}
Point Intersection(const Line &a, const Line &b) {
    T d1 = cross(a.b - a.a, b.b - b.a);
    T d2 = cross(a.b - a.a, a.b - b.a);
    if (eq(d1, 0.) and eq(d2, 0.))
        return b.a;
    return b.a + (b.b - b.a) * (d2 / d1);
}
Poly Intersection(const Circle &a, const Line &b) {
    Poly res;
    T d = Dist(b, a.p);
    if (d > a.r + eps)
        return res;
    Point h = Projection(b, a.p);
    if (eq(d, a.r)) {
        res.push_back(h);
        return res;
    }
    Point e = unit(b.b - b.a);
    T ph = sqrt(a.r * a.r - d * d);
    res.push_back(h - e * ph);
    res.push_back(h + e * ph);
    return res;
}
Poly Intersection(const Circle &a, const Segment &b) {
    Line c(b.a, b.b);
    Poly sub = Intersection(a, c);
    double xmi = min(b.a.X, b.b.X), xma = max(b.a.X, b.b.X);
    double ymi = min(b.a.Y, b.b.Y), yma = max(b.a.Y, b.b.Y);
    Poly res;
    rep(i, 0, sub.size()) {
        if (xmi <= sub[i].X + eps and sub[i].X - eps <= xma and
            ymi <= sub[i].Y + eps and sub[i].Y - eps <= yma) {
            res.push_back(sub[i]);
        }
    }
    return res;
}
Poly Intersection(const Circle &a, const Circle &b) {
    Poly res;
    int mode = isIntersect(a, b);
    T d = abs(a.p - b.p);
    if (mode == 4 or mode == 0)
        return res;
    if (mode == 3) {
        T t = a.r / (a.r + b.r);
        res.push_back(a.p + (b.p - a.p) * t);
        return res;
    }
    if (mode == 1) {
        if (b.r < a.r - eps) {
            res.push_back(a.p + (b.p - a.p) * (a.r / d));
        } else {
            res.push_back(b.p + (a.p - b.p) * (b.r / d));
        }
        return res;
    }
    T rc = (a.r * a.r + d * d - b.r * b.r) / d / 2.;
    T rs = sqrt(a.r * a.r - rc * rc);
    if (a.r - abs(rc) < eps)
        rs = 0;
    Point e = unit(b.p - a.p);
    res.push_back(a.p + rc * e + rs * e * Point(0, 1));
    res.push_back(a.p + rc * e + rs * e * Point(0, -1));
    return res;
}
Poly HalfplaneIntersection(vector<Line> &H) {
    sort(ALL(H), [&](Line &l1, Line &l2) { return cmp(l1.dir, l2.dir); });
    auto outside = [&](Line &L, Point p) -> bool {
        return cross(L.dir, p - L.a) < -eps;
    };
    deque<Line> deq;
    int sz = 0;
    rep(i, 0, SZ(H)) {
        while (sz > 1 and
               outside(H[i], Intersection(deq[sz - 1], deq[sz - 2]))) {
            deq.pop_back();
            sz--;
        }
        while (sz > 1 and outside(H[i], Intersection(deq[0], deq[1]))) {
            deq.pop_front();
            sz--;
        }
        if (sz > 0 and fabs(cross(H[i].dir, deq[sz - 1].dir)) < eps) {
            if (dot(H[i].dir, deq[sz - 1].dir) < 0) {
                return {};
            }
            if (outside(H[i], deq[sz - 1].a)) {
                deq.pop_back();
                sz--;
            } else
                continue;
        }
        deq.push_back(H[i]);
        sz++;
    }

    while (sz > 2 and outside(deq[0], Intersection(deq[sz - 1], deq[sz - 2]))) {
        deq.pop_back();
        sz--;
    }
    while (sz > 2 and outside(deq[sz - 1], Intersection(deq[0], deq[1]))) {
        deq.pop_front();
        sz--;
    }
    if (sz < 3)
        return {};
    deq.push_back(deq.front());
    Poly ret;
    rep(i, 0, sz) ret.push_back(Intersection(deq[i], deq[i + 1]));
    return ret;
}

T Area(const Poly &a) {
    T res = 0;
    int n = a.size();
    rep(i, 0, n) res += cross(a[i], a[(i + 1) % n]);
    return fabs(res / 2.);
}
T Area(const Poly &a, const Circle &b) {
    int n = a.size();
    if (n < 3)
        return .0;
    auto rec = [&](auto self, const Circle &c, const Point &p1,
                   const Point &p2) {
        Point va = c.p - p1, vb = c.p - p2;
        T f = cross(va, vb), res = .0;
        if (eq(f, .0))
            return res;
        if (max(abs(va), abs(vb)) < c.r + eps)
            return f;
        if (Dist(Segment(p1, p2), c.p) > c.r - eps)
            return c.r * c.r * arg(vb * conj(va));
        auto u = Intersection(c, Segment(p1, p2));
        Poly sub;
        sub.push_back(p1);
        for (auto &x : u)
            sub.push_back(x);
        sub.push_back(p2);
        rep(i, 0, sub.size() - 1) res += self(self, c, sub[i], sub[i + 1]);
        return res;
    };
    T res = .0;
    rep(i, 0, n) res += rec(rec, b, a[i], a[(i + 1) % n]);
    return fabs(res / 2.);
}
T Area(const Circle &a, const Circle &b) {
    T d = abs(a.p - b.p);
    if (d >= a.r + b.r - eps)
        return .0;
    if (d <= abs(a.r - b.r) + eps) {
        T r = min(a.r, b.r);
        return M_PI * r * r;
    }
    T ath = acos((a.r * a.r + d * d - b.r * b.r) / d / a.r / 2.);
    T res = a.r * a.r * (ath - sin(ath * 2) / 2.);
    T bth = acos((b.r * b.r + d * d - a.r * a.r) / d / b.r / 2.);
    res += b.r * b.r * (bth - sin(bth * 2) / 2.);
    return fabs(res);
}
bool isConvex(const Poly &a) {
    int n = a.size();
    int cur, pre, nxt;
    rep(i, 0, n) {
        pre = (i - 1 + n) % n;
        nxt = (i + 1) % n;
        cur = i;
        if (ccw(a[pre], a[cur], a[nxt]) == -1)
            return 0;
    }
    return 1;
}
int isContained(const Poly &a,
                const Point &b) { // 0:not contain,1:on edge,2:contain

    bool res = 0;
    int n = a.size();
    rep(i, 0, n) {
        Point p = a[i] - b, q = a[(i + 1) % n] - b;
        if (p.Y > q.Y)
            swap(p, q);
        if (p.Y < eps and eps < q.Y and cross(p, q) > eps)
            res ^= 1;
        if (eq(cross(p, q), .0) and dot(p, q) < eps)
            return 1;
    }
    return (res ? 2 : 0);
}
Poly ConvexHull(Poly &a) {
    sort(ALL(a), [](const Point &p, const Point &q) {
        return (eq(p.Y, q.Y) ? p.X < q.X : p.Y < q.Y);
    });
    a.erase(unique(ALL(a)), a.end());
    int n = a.size(), k = 0;
    Poly res(n * 2);
    for (int i = 0; i < n; res[k++] = a[i++]) {
        while (k >= 2 and
               cross(res[k - 1] - res[k - 2], a[i] - res[k - 1]) < eps)
            k--;
    }
    for (int i = n - 2, t = k + 1; i >= 0; res[k++] = a[i--]) {
        while (k >= t and
               cross(res[k - 1] - res[k - 2], a[i] - res[k - 1]) < eps)
            k--;
    }
    res.resize(k - 1);
    return res;
}
T Diam(const Poly &a) {
    int n = a.size();
    int x = 0, y = 0;
    rep(i, 1, n) {
        if (a[i].Y > a[x].Y)
            x = i;
        if (a[i].Y < a[y].Y)
            y = i;
    }
    T res = abs(a[x] - a[y]);
    int i = x, j = y;
    do {
        if (cross(a[(i + 1) % n] - a[i], a[(j + 1) % n] - a[j]) < 0)
            i = (i + 1) % n;
        else
            j = (j + 1) % n;
        chmax(res, abs(a[i] - a[j]));
    } while (i != x or j != y);
    return res;
}
Poly Cut(const Poly &a, const Line &l) {
    int n = a.size();
    Poly res;
    rep(i, 0, n) {
        Point p = a[i], q = a[(i + 1) % n];
        if (ccw(l.a, l.b, p) != -1)
            res.push_back(p);
        if (ccw(l.a, l.b, p) * ccw(l.a, l.b, q) < 0)
            res.push_back(Intersection(Line(p, q), l));
    }
    return res;
}

T Closest(Poly &a) {
    int n = a.size();
    if (n <= 1)
        return 0;
    sort(ALL(a), [&](Point a, Point b) {
        return (eq(a.X, b.X) ? a.Y < b.Y : a.X < b.X);
    });
    Poly buf(n);
    auto rec = [&](auto self, int lb, int rb) -> T {
        if (rb - lb <= 1)
            return (T)INF;
        int mid = (lb + rb) >> 1;
        auto x = a[mid].X;
        T res = min(self(self, lb, mid), self(self, mid, rb));
        inplace_merge(a.begin() + lb, a.begin() + mid, a.begin() + rb,
                      [&](auto p, auto q) { return p.Y < q.Y; });
        int ptr = 0;
        rep(i, lb, rb) {
            if (abs(a[i].X - x) >= res)
                continue;
            rep(j, 0, ptr) {
                auto sub = a[i] - buf[ptr - 1 - j];
                if (sub.Y >= res)
                    break;
                chmin(res, abs(sub));
            }
            buf[ptr++] = a[i];
        }
        return res;
    };
    return rec(rec, 0, n);
}

Circle Incircle(const Point &a, const Point &b, const Point &c) {
    T A = abs(b - c), B = abs(c - a), C = abs(a - b);
    Point p(A * a.X + B * b.X + C * c.X, A * a.Y + B * b.Y + C * c.Y);
    p /= (A + B + C);
    T r = Dist(Line(a, b), p);
    return Circle(p, r);
}
Circle Circumcircle(const Point &a, const Point &b, const Point &c) {
    Line l1((a + b) / 2., (a + b) / 2. + (b - a) * Point(0, 1));
    Line l2((b + c) / 2., (b + c) / 2. + (c - b) * Point(0, 1));
    Point p = Intersection(l1, l2);
    return Circle(p, abs(p - a));
}
Poly tangent(const Point &a, const Circle &b) {
    return Intersection(b, Circle(a, sqrt(norm(b.p - a) - b.r * b.r)));
}
vector<Line> tangent(const Circle &a, const Circle &b) {
    vector<Line> res;
    T d = abs(a.p - b.p);
    if (eq(d, 0.))
        return res;
    Point u = unit(b.p - a.p);
    Point v = u * Point(0, 1);
    for (int t : {-1, 1}) {
        T h = (a.r + b.r * t) / d;
        if (eq(h * h, 1.)) {
            res.push_back(Line(a.p + (h > 0 ? u : -u) * a.r,
                               a.p + (h > 0 ? u : -u) * a.r + v));
        } else if (1 > h * h) {
            Point U = u * h, V = v * sqrt(1 - h * h);
            res.push_back(Line(a.p + (U + V) * a.r, b.p - (U + V) * (b.r * t)));
            res.push_back(Line(a.p + (U - V) * a.r, b.p - (U - V) * (b.r * t)));
        }
    }
    return res;
}

/**
 * @brief Geometry
 */

struct Compare {
    bool operator()(const pair<double, vector<complex<double>>>& A,
                    const pair<double, vector<complex<double>>>& B) {
        return A.first > B.first;
    }
};

void Solve(int N, int K) {
    map<pair<double,double>,int> ID;
    vector<Point> P(N);
    rep(i,0,N) {
        double x, y;
        cin >> x >> y;
        P[i] = Point(x,y);
        ID[{x,y}] = i;
    }
    auto isSimple = [&](Poly Q) -> bool {
        int M = Q.size();
        rep(i,0,M) {
            int ni = (i+1)%M;
            rep(j,0,M) {
                int nj = (j+1)%M;
                if (i == j || i == nj || ni == j) continue;
                if (isIntersect(Segment(Q[i],Q[ni]),Segment(Q[j],Q[nj]))) {
                    return false;
                }
            }
        }
        return true;
    };
    auto isValid = [&](Poly Q) -> bool {
        rep(i,0,N) {
            if (isContained(Q,P[i]) == 0) return false;
        }
        return true;
    };
    auto CalcLen = [&](Poly Q) -> double {
        int M = Q.size();
        double Ret = 0.0;
        rep(i,0,M) {
            int ni = (i+1)%M;
            Ret += abs(Q[ni]-Q[i]);
        }
        return Ret;
    };
    Poly PP = P;
    Poly MAX = ConvexHull(PP);
    priority_queue<pair<double,Poly>,vector<pair<double,Poly>>,Compare> PQ;
    map<vector<int>,bool> mp;
    PQ.push({CalcLen(MAX),MAX});
    rep(_,0,K) {
        if (PQ.empty()) {
            cout << -1 << endl;
            return;
        }
        auto [D,Q] = PQ.top();
        int M = Q.size();
        PQ.pop();
        vector<bool> B(N, true);
        vector<int> A;
        rep(i,0,M) {
            int j = ID[{Q[i].real(),Q[i].imag()}];
            B[j] = false, A.push_back(j);
        }
        if (mp.count(A)) {
            _--;
            continue;
        }
        if (_ == K-1) {
            printf("%.12f\n", D);
            return;
        }
        mp[A] = true;
        rep(i,0,N) {
            if (!B[i]) continue;
            rep(j,0,M) {
                Poly New;
                if (j == M-1) {
                    rep(k,0,M) New.push_back(Q[k]);
                    New.push_back(P[i]);
                }
                else {
                    rep(k,0,j+1) New.push_back(Q[k]);
                    New.push_back(P[i]);
                    rep(k,j+1,M) New.push_back(Q[k]);
                }
                if (isSimple(New) && isValid(New)) {
                    PQ.push({CalcLen(New),New});
                }
            }
        }
    }
    cout << -1 << endl;
}

int main() {
while(1) {
    int N, K;
    cin >> N >> K;
    if (N == 0) return 0;
    Solve(N,K);
}   
}
accuracy: 1
time_ms: 40
memory_kb: 3828
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
#define all(A) A.begin(),A.end()
#define ALL(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)
template<class T>
bool chmax(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p < q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

template<class T>
bool chmin(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p > q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

#include<complex>
const int INF = 1000000000;
const ll LINF = 1001002003004005006ll;
int dx[] = { 1,0,-1,0 }, dy[] = { 0,1,0,-1 };

struct IOSetup {
    IOSetup() {
        cin.tie(0);
        ios::sync_with_stdio(0);
        cout << fixed << setprecision(12);
    }
} iosetup;

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    return os;
}
template<typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v)is >> x;
    return is;
}

// line 1 "Geometry/template.cpp"
// Real
using Real = double;
const Real EPS = 1e-6;
const Real pi = acosl(-1);

// Point
using Point = complex<Real>;
istream& operator>>(istream& is, Point& p) {
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}
ostream& operator<<(ostream& os, Point& p) {
    return os << fixed << setprecision(12) << p.real() << ' ' << p.imag();
}
inline bool eq(Real a, Real b) {
    return fabs(a - b) < EPS;
}
Point operator*(const Point& p, const Real& d) {
    return Point(real(p) * d, imag(p) * d);
}

// Line
struct Line {
    Point p1, p2;
    Line() = default;
    Line(Point p1, Point p2) :p1(p1), p2(p2) {}
    //Ax + By = C
    Line(Real A, Real B, Real C) {
        if (eq(A, 0))     p1 = Point(0, C / B), p2 = Point(1, C / B);
        else if (eq(B, 0))p1 = Point(C / A, 0), p2 = Point(C / A, 1);
        else            p1 = Point(0, C / B), p2 = Point(C / A, 0);
    }
};

// Segment
struct Segment :Line {
    Segment() = default;
    Segment(Point p1, Point p2) :Line(p1, p2) {}
};
Real dot(Point a, Point b) {
    return real(a) * real(b) + imag(a) * imag(b);
}
Real cross(Point a, Point b) {
    return real(a) * imag(b) - imag(a) * real(b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    if (cross(b, c) > EPS)       return  1;//COUNTER CLOCKWISE
    else if (cross(b, c) < -EPS) return -1;//CLOCKWISE
    else if (dot(b, c) < 0)      return  2;//c--a--b ONLINE BACK
    else if (norm(b) < norm(c)) return -2;//a--b--c ONLINE FRONT
    else                     return  0;//a--c--b ON SEGMENT
}
Point projection(Segment l, Point p) {
    Real k = dot(l.p1 - l.p2, p - l.p1) / norm(l.p1 - l.p2);
    return l.p1 + (l.p1 - l.p2) * k;
}
bool intersect(Segment s, Segment t) {
    return ccw(s.p1, s.p2, t.p1) * ccw(s.p1, s.p2, t.p2) < EPS && ccw(t.p1, t.p2, s.p1) * ccw(t.p1, t.p2, s.p2) < EPS;
}
bool intersect(Segment s, Point p) {
    return ccw(s.p1, s.p2, p) == 0;
}
Real dis(Point a, Point b) {
    return abs(a - b);
}
Real dis(Segment s, Point p) {
    Point r = projection(s, p);
    if (intersect(s, r)) return abs(r - p);
    return min(abs(s.p1 - p), abs(s.p2 - p));
}

int contains(vll V,vector<Point> P, Point p) {
    int res = 0;
    int n = (int)V.size();
    for (int i = 0; i < n; i++) {
        Point a = P[V[i]] - p, b = P[V[(i + 1) % n]] - p;
        if (imag(a) > imag(b)) swap(a, b);
        if (imag(a) <= 0 && 0 < imag(b) && cross(a, b) < 0) res ^= 1;
        if (eq(cross(a, b), 0) && (dot(a, b) < 0 || eq(dot(a, b), 0))) return 1;
    }
    if (res) res = 2;
    return res;
}

vector<ll> convex_hull(vector<Point> p) {
    int n = (int)p.size(), k = 0;
    // if (n <= 2)return p;
    sort(begin(p), end(p), [](Point a, Point b) {
        return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
        });
    vector<ll>ch(2 * n);
    for (int i = 0; i < n; ch[k++] = i++) {
        // while(k>=2 and cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<EPS)k--;
        while (k >= 2 && cross(p[ch[k - 1]] - p[ch[k - 2]], p[i] - p[ch[k - 1]]) < 0)k--;
    }
    for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = i--) {
        // while(k>=t and cross(ch[k-1]-ch[k-2],p[i]-ch[k-1])<EPS)k--;
        while (k >= t && cross(p[ch[k - 1]] - p[ch[k - 2]], p[i] - p[ch[k - 1]]) < 0)k--;
    }
    ch.resize(k - 1);
    return ch;
}

bool is_valid(vll V, vector<Point>& P) {
    ll VN = V.size();
    rep(i, VN)rep(j, i) {
        if (abs(i - j) <= 1 || (i == VN - 1 && j == 0))continue;
        Segment S1 = Segment(P[V[i]], P[V[(i + 1) % VN]]);
        Segment S2 = Segment(P[V[j]], P[V[(j + 1) % VN]]);
        if (intersect(S1, S2))return 0;
    }
    for(auto p:P)if(contains(V,P,p)==0)return 0;
    return 1;
}

double len(vll V, vector<Point>& P) {
    double res = 0.0;
    ll VN = V.size();
    rep(i, VN)res += dis(P[V[i]], P[V[(i + 1) % VN]]);
    return res;
}

void solve(ll N, ll K) {

    vector<Point> P(N);
    rep(i, N)cin >> P[i];
    sort(begin(P), end(P), [](Point a, Point b) {
        return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);

        });
    vll Con = convex_hull(P);
    priority_queue<pair<double, vll>, vector<pair<double, vll>>, greater<pair<double, vll>>> Q;
    Q.push({ len(Con,P),Con });
    set<vll> seen;
    double an;
    while (K > 0) {
        if (Q.size() == 0) {
            an = 1e18;
            break;
        }
        auto C = Q.top().second;
        an = Q.top().first;
        Q.pop();
        if (seen.count(C))continue;
        K--;
        seen.insert(C);
        vector<bool> US(N, 0);
        for (auto c : C)US[c] = 1;
        ll CN = C.size();
        ll cnt = 0;
        rep(j, N) {
            if (US[j])continue;
            rep(n, CN) {
                cnt++;
                vll NC;
                rep(k, CN) {
                    NC.push_back(C[k]);
                    if (k == n)NC.push_back(j);
                }
                if (is_valid(NC, P) && !seen.count(NC)) {
                    Q.push({ len(NC,P),NC });
                }
            }
        }
    }

    cout << fixed << setprecision(15);
    cout << (an < 1e17 ? an : -1) << endl;
    return;
}


int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    ll N, K;
    while (cin >> N >> K, N != 0)solve(N, K);

}
accuracy: 1
time_ms: 60
memory_kb: 3716
final_rank: 9

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

using f64 = long double;

template < class T > vector< T >& operator++(vector< T >& a) { for(T& x : a) x++; return a; }
template < class T > vector< T >& operator--(vector< T >& a) { for(T& x : a) x--; return a; }
template < class T > vector< T >  operator++(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x++; return res; }
template < class T > vector< T >  operator--(vector< T >& a, signed) { vector< T > res = a; for(T& x : a) x--; return res; }

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

template < class T > struct point {
    T x, y;
    point() : x(0), y(0) {}
    point(T x, T y) : x(x), y(y) {}
    point(std::pair< T, T > p) : x(p.first), y(p.second) {}
    point& operator+=(const point& p) { x += p.x, y += p.y; return *this; }
    point& operator-=(const point& p) { x -= p.x, y -= p.y; return *this; }
    point& operator*=(const T r) { x *= r, y *= r; return *this; }
    point& operator/=(const T r) { x /= r, y /= r; return *this; }
    point operator+(const point& p) const { return point(*this) += p; }
    point operator-(const point& p) const { return point(*this) -= p; }
    point operator*(const T r) const { return point(*this) *= r; }
    point operator/(const T r) const { return point(*this) /= r; }
    point operator-() const { return {-x, -y}; }
    bool operator==(const point& p) const { return x == p.x and y == p.y; }
    bool operator!=(const point& p) const { return x != p.x or  y != p.y; }
    bool operator<(const point& p) const { return x == p.x ? y < p.y : x < p.x; }
    point< T > rot(double theta) {
        static_assert(is_floating_point_v< T >);
        double cos_ = std::cos(theta), sin_ = std::sin(theta);
        return {cos_ * x - sin_ * y, sin_ * x + cos_ * y};
    }
};
template < class T > istream& operator>>(istream& is, point< T >& p) { return is >> p.x >> p.y; }
template < class T > ostream& operator<<(ostream& os, point< T >& p) { return os << p.x << " " << p.y; }
template < class T > T dot(const point< T >& a, const point< T >& b) { return a.x * b.x + a.y * b.y; }
template < class T > T det(const point< T >& a, const point< T >& b) { return a.x * b.y - a.y * b.x; }
template < class T > T norm(const point< T >& p) { return p.x * p.x + p.y * p.y; }
template < class T > double abs(const point< T >& p) { return std::sqrt(norm(p)); }
template < class T > double angle(const point< T >& p) { return std::atan2(p.y, p.x); }
template < class T > int sign(const T x) {
    T e = (is_integral_v< T > ? 1 : 1e-8);
    if(x <= -e) return -1;
    if(x >= +e) return +1;
    return 0;
}
template < class T > bool equals(const T& a, const T& b) { return sign(a - b) == 0; }
template < class T > int ccw(const point< T >& a, point< T > b, point< T > c) {
    b -= a, c -= a;
    if(sign(det(b, c)) == +1) return +1; // counter clockwise
    if(sign(det(b, c)) == -1) return -1; //         clockwise
    if(sign(dot(b, c)) == -1) return +2; // c-a-b
    if(norm(b) < norm(c)) return -2;     // a-b-c
    return 0;                            // a-c-b
}

template < class T > struct line {
    point< T > a, b;
    line() {}
    line(point< T > a, point< T > b) : a(a), b(b) {}
};
template < class T > point< T > projection(const line< T >& l, const point< T >& p) {
    static_assert(is_floating_point_v< T >);
    return l.a + (l.a - l.b) * dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
}
template < class T > point< T > reflection(const line< T >& l, const point< T >& p) {
    static_assert(is_floating_point_v< T >);
    return p + (projection(l, p) - p) * T(2);
}
template < class T > bool orthogonal(const line< T >& a, const line< T >& b) { return equals(dot(a.b - a.a, b.b - b.a), T(0)); }
template < class T > bool parallel  (const line< T >& a, const line< T >& b) { return equals(det(a.b - a.a, b.b - b.a), T(0)); }
template < class T > point< T > cross_point_ll(const line< T >& l, const line< T >& m) {
    static_assert(is_floating_point_v< T >);
    T A = det(l.b - l.a, m.b - m.a);
    T B = det(l.b - l.a, l.b - m.a);
    if(equals(abs(A), T(0)) and equals(abs(B), T(0))) return m.a;
    return m.a + (m.b - m.a) * B / A;
}

template < class T > using segment = line< T >;
template < class T > bool intersect_ss(const segment< T >& s, const segment< T >& t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 and ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
template < class T > double distance_sp(const segment< T >& s, const point< T >& p) {
    static_assert(is_floating_point_v< T >);
    point r = projection(s, p);
    if(ccw(s.a, s.b, r) == 0) return abs(r - p);
    return std::min(abs(s.a - p), abs(s.b - p));
}
template < class T > double distance_ss(const segment< T >& a, const segment< T >& b) {
    if(intersect_ss(a, b)) return 0;
    return std::min({ distance_sp(a, b.a), distance_sp(a, b.b), distance_sp(b, a.a), distance_sp(b, a.b) });
}

template < class T > using polygon = std::vector< point< T > >;
template < class T > T area2(const polygon< T >& p) {
    T s = 0;
    int n = p.size();
    for(int i = 0; i < n; i++) s += det(p[i], p[(i + 1) % n]);
    return s;
}
template < class T > T area(const polygon< T >& p) { return area2(p) / T(2); }

template < class T > bool is_convex(const polygon< T >& p) {
    int n = p.size();
    for(int i = 0; i < n; i++) if(ccw(p[(i - 1 + n) % n], p[i], p[(i + 1) % n]) == -1) return false;
    return true;
}
template < class T > int contains(const polygon< T >& g, const point< T >& p) {
    int n = g.size();
    bool in = false;
    for(int i = 0; i < n; i++) {
        point a = g[i] - p, b = g[(i + 1) % n] - p;
        if(sign(a.y - b.y) == +1) std::swap(a, b);
        if(sign(a.y) <= 0 and sign(b.y) ==+1 and sign(det(a, b)) == -1) in = !in;
        if(sign(det(a, b)) == 0 and sign(dot(a, b)) <= 0) return 1; // ON
    }
    return in ? 2 : 0;
}
template < class T > polygon< T > convex_cut(const polygon< T >& p, const line< T >& l) {
    int n = p.size();
    polygon< T > res;
    for(int i = 0; i < n; i++) {
        point now = p[i], nxt = p[(i + 1) % n];
        if(ccw(l.a, l.b, now) != -1) res.push_back(now);
        if(ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0) res.push_back(cross_point_ll(line(now, nxt), l));
    }
    return res;
}
template < class T > pair<vector<int>, polygon< T >> convex_hull(polygon< T >& p) {
    int n = p.size(), k = 0;
    if(n == 1) return {{0}, p};
    if(n == 2) return {{0, 1}, p};
    std::sort(p.begin(), p.end());
    vector<int> id(n + n);
    polygon< T > ch(n + n);
    for(int i = 0; i < n; id[k] = i, ch[k++] = p[i++])
        while(k >= 2 and sign(det(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1])) == -1) k--;
    for(int i = n - 2, t = k + 1; i >= 0; id[k] = i, ch[k++] = p[i--])
        while(k >= t and sign(det(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1])) == -1) k--;
    id.resize(k - 1);
    ch.resize(k - 1);
    return {id, ch};
}
template < class T > T diameter2(const polygon< T >& p) {
    static_assert(is_floating_point_v< T >);
    int n = p.size(), is = 0, js = 0;
    for(int i = 1; i < n; i++) {
        if(sign(p[i].y - p[is].y) == +1) is = i;
        if(sign(p[i].y - p[js].y) == -1) js = i;
    }
    T dist_max = norm(p[is] - p[js]);
    int maxi = is, i = is, maxj = js, j = js;
    do {
        if(sign(det(p[(i + 1) % n] - p[i], p[(j + 1) % n] - p[j])) >= 0) j = (j + 1) % n; else i = (i + 1) % n;
        if(norm(p[i] - p[j]) > dist_max) {
            dist_max = norm(p[i] - p[j]);
            maxi = i, maxj = j;
        }
    } while(i != is or j != js);
    return dist_max;
}
template < class T > double diameter(const polygon< T >& p) {
    static_assert(is_floating_point_v< T >);
    return std::sqrt(diameter2(p));
}

template < class T > struct circle {
    point< T > p;
    T r;
    circle() = default;
    circle(point< T > p, T r) : p(p), r(r) {}
};
template < class T > istream& operator>>(istream& is, circle< T >& c) { return is >> c.p >> c.r; }
template < class T > int intersect_cc(circle< T > c1, circle< T > c2) {
    if(c1.r < c2.r) std::swap(c1, c2);
    T d = abs(c1.p - c2.p);
    if(sign(c1.r + c2.r - d) == -1) return 4;
    if(equals(c1.r + c2.r, d)) return 3;
    if(sign(c1.r - c2.r - d) == -1) return 2;
    if(equals(c1.r - c2.r, d)) return 1;
    return 0;
}
template < class T > std::pair<point< T >, point< T >> cross_point_cc(const circle< T >& c1, const circle< T >& c2) {
    T d = abs(c1.p - c2.p);
    T a = std::acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    T t = angle(c2.p - c1.p);
    point< T > p1 = c1.p + point< T >(std::cos(t + a), std::sin(t + a)) * c1.r;
    point< T > p2 = c1.p + point< T >(std::cos(t - a), std::sin(t - a)) * c1.r;
    return {p1, p2};
}

f64 solve(int N, int K) {
    vector<point<int>> P(N);
    for(int i : rep(N)) P[i].x = in(), P[i].y = in();
    vector<int> s = convex_hull(P).first;
    auto len = [&](vector<int> I) -> f64 {
        f64 res = 0;
        const int n = I.size();
        for(int i : rep(n)) res += abs(P[I[i]] - P[I[(i + 1) % n]]);
        return res;
    };
    set<vector<int>> st;
    heap_min<pair<f64,vector<int>>> q;
    q.push({len(s), s});
    st.insert(s);
    for(int _ : rep(K - 1)) {
        if(q.empty()) break;
        auto [_len, vec] = q.top(); q.pop();
        vector<int> used(N, false);
        for(int i : vec) used[i] = true;
        for(int i : rep(N)) if(not used[i]) {
            used[i] = true;
            const int m = vec.size();
            for(int pos : rep(m)) {
                vector<int> I = vec;
                I.insert(I.begin() + pos, {i});
                const int nI = I.size();

                bool ok = [&] {
                    for(int i : rep(nI)) {
                        vector<int> A;
                        for(int k : rep(nI)) A.push_back(I[(i + k) % nI]);
                        if(st.count(A)) return false;
                    }
                    reverse(I);
                    for(int i : rep(nI)) {
                        vector<int> A;
                        for(int k : rep(nI)) A.push_back(I[(i + k) % nI]);
                        if(st.count(A)) return false;
                    }
                    reverse(I);

                    for(int p : rep(nI)) {
                        for(int q : rep(nI)) if(p != q) {
                            segment<int> s1(P[I[p]], P[I[(p + 1) % nI]]);
                            segment<int> s2(P[I[q]], P[I[(q + 1) % nI]]);
                            if(I[p] == I[(q + 1) % nI]) continue;
                            if(I[q] == I[(p + 1) % nI]) continue;
                            if(intersect_ss(s1, s2)) return false;
                        }
                    }

                    for(int v : rep(N)) if(not used[v]) {
                        segment<int> s1(P[v], point<int>(200, 201));
                        int cnt = 0;
                        for(int p : rep(nI)) {
                            segment<int> s2(P[I[p]], P[I[(p + 1) % nI]]);
                            if(intersect_ss(s1, s2)) cnt++;
                        }
                        if(cnt % 2 == 0) return false;
                    }

                    return true;
                }();

                if(ok) {
                    q.push({len(I), I});
                    st.insert(I);
                }
            }
            used[i] = false;
        }
    }

    if(q.empty()) return -1e9;
    return q.top().first;
}

int main() {
    while(true) {
        int N = in(), K = in();
        if(make_pair(N, K) == make_pair(0, 0)) return 0;
        f64 res = solve(N, K);
        if(res < 0) {
            print("-1");
        } else {
            printer::precision(20);
            print(res);
        }
    }
}
accuracy: 1
time_ms: 100
memory_kb: 3700
final_rank: 8

code_snippet: #include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;
using lint = long long;
using P = pair<lint, lint>;
using Pii = pair<int, int>;
using ull = unsigned long long;

struct FastIO {
    FastIO() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} aaaAAAaaaAAA;

#define TYPE(n) decltype(n)

#define rep(i, n) for (TYPE(n) i = 0; i < (n); ++i)
#define repe(i, n) for (TYPE(n) i = 0; i <= (n); ++i)
#define rep1(i, n) for (TYPE(n) i = 1; i < (n); ++i)
#define rep1e(i, n) for (TYPE(n) i = 1; i <= (n); ++i)
#define repn(i, a, b) for (TYPE(a) i = (a); i < (b); ++i)
#define repne(i, a, b) for (TYPE(a) i = (a); i <= (b); ++i)
#define rrep(i, n) for (TYPE(n) i = (n); i >= 0; --i)
#define all(vec) begin(vec), end(vec)
#define rall(vec) rbegin(vec), rend(vec)

constexpr long long Mod = /** 1000'000'007LL /*/ 998244353LL /**/;
constexpr long long Inf = 2'000'000'000'000'000'010LL;
constexpr int IntInf = 1000'000'010;
constexpr double Pi = 3.141592653589793238;
constexpr double InvPi = 0.318309886183790671;

const int di[] = {0, -1, 0, 1, 0};
const int dj[] = {1, 0, -1, 0, 0};

template <typename T>
using prique = priority_queue<T>;
template <typename T>
using prique_inv = priority_queue<T, vector<T>, greater<T>>;
template <typename T>
inline istream& operator>>(istream& is, vector<T>& v) {
    for (auto& e : v) is >> e;
    return is;
}
template <typename T>
inline ostream& operator<<(ostream& os, const vector<T>& v) {
    for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
        os << *itr;
        if (++itr != end_itr) os << " ";
    }
    return os;
}
template <typename T, typename U>
inline bool chmin(T& a, const U b) {
    return a > b ? a = b, true : false;
}
template <typename T, typename U>
inline bool chmax(T& a, const U b) {
    return a < b ? a = b, true : false;
}
template <typename T, typename U>
inline istream& operator>>(istream& is, pair<T, U>& rhs) {
    return is >> rhs.first >> rhs.second;
}
template <typename T, typename U>
inline ostream& operator<<(ostream& os, const pair<T, U>& rhs) {
    return os << "{" << rhs.first << ", " << rhs.second << "}";
}

namespace geometry {

using floating_point_type = double;

constexpr floating_point_type EPS = 1e-13;
constexpr floating_point_type Pi = 3.141592653589793;

// constexpr floating_point_type operator"" _deg(floating_point_type deg) { return static_cast<floating_point_type>(deg * Pi / 180.0); }
constexpr floating_point_type operator"" _deg(unsigned long long deg) { return static_cast<floating_point_type>(deg * Pi / 180.0); }

template <typename T>
constexpr int sgn(T a) noexcept {
    return (a < -EPS ? -1 : (a > EPS ? +1 : 0));
}

template <typename T, typename U>
constexpr bool same(T a, U b) noexcept {
    return sgn(a - b) == 0;
}

template <typename T>
constexpr T square(T x) noexcept {
    return x * x;
}

// ax + by + c = 0, gcd(a,b,c) = 1
// a != 0 : a > 0
// a = 0: b > 0
tuple<long long, long long, long long> general_form(long long x1, long long y1, long long x2, long long y2) {
    long long a = y1 - y2, b = x2 - x1, c = x1 * y2 - x2 * y1;
    if (a < 0) a = -a, b = -b, c = -c;
    if (a == 0 && b < 0) b = -b, c = -c;
    long long g = gcd(gcd(a, b), c);
    return {a / g, b / g, c / g};
}

template <typename T>
struct Vector2D {
    using value_type = T;
    T x, y;

    Vector2D() = default;
    explicit Vector2D(T arg) : x(cos(arg)), y(sin(arg)) {}
    constexpr Vector2D(T x, T y) noexcept : x(x), y(y) {}

    constexpr bool operator<(const Vector2D& v) const noexcept {
        if (!same(x, v.x)) return x < v.x;
        return y < v.y;
    }
    constexpr bool operator>(const Vector2D& v) const noexcept { return v < *this; }
    constexpr bool operator==(const Vector2D& v) const noexcept { return same(x, v.x) && same(y, v.y); }
    constexpr bool operator!=(const Vector2D& v) const noexcept { return !(*this == v); }

    constexpr Vector2D operator+() const noexcept { return *this; }
    constexpr Vector2D operator-() const noexcept { return {-x, -y}; }

    constexpr Vector2D operator+(const Vector2D& v) const noexcept { return {x + v.x, y + v.y}; }
    constexpr Vector2D operator-(const Vector2D& v) const noexcept { return {x - v.x, y - v.y}; }
    constexpr Vector2D operator*(T s) const noexcept { return {x * s, y * s}; }
    constexpr Vector2D operator/(T s) const noexcept { return {x / s, y / s}; }

    constexpr Vector2D& operator+=(const Vector2D& v) noexcept {
        x += v.x;
        y += v.y;
        return *this;
    }
    constexpr Vector2D& operator-=(const Vector2D& v) noexcept {
        x -= v.x;
        y -= v.y;
        return *this;
    }
    constexpr Vector2D& operator*=(T s) noexcept {
        x *= s;
        y *= s;
        return *this;
    }
    constexpr Vector2D& operator/=(T s) noexcept {
        x /= s;
        y /= s;
        return *this;
    }

    constexpr bool isZero() const noexcept { return x == T(0) && y == T(0); }
    bool hasNan() const { return isnan(x) || isnan(y); }

    constexpr T dot(const Vector2D& v) const noexcept { return x * v.x + y * v.y; }
    constexpr T cross(const Vector2D& v) const noexcept { return x * v.y - y * v.x; }

    floating_point_type length() const {
        if (isZero()) return 0.0;

        const T abs_x = std::abs(x);
        const T abs_y = std::abs(y);

        const auto [u, v] = std::minmax(abs_x, abs_y);
        const T t = u / v;

        return v * std::sqrt(std::fma(t, t, 1.0));
    }
    constexpr T lengthSq() const noexcept { return dot(*this); }

    floating_point_type distanceFrom(const Vector2D& v) const { return (v - *this).length(); }
    constexpr T distanceFromSq(const Vector2D& v) const noexcept { return (v - *this).lengthSq(); }

    Vector2D normalized() const { return *this / length(); }
    Vector2D& normalize() { return *this /= length(); }

    Vector2D rotated(floating_point_type angle) const {
        const T s = sin(angle);
        const T c = cos(angle);
        return {x * c - y * s, x * s + y * c};
    }
    Vector2D& rotate(floating_point_type angle) { return *this = rotated(angle); }

    floating_point_type arg() const { return atan2<floating_point_type>(y, x); }
    floating_point_type arg(const Vector2D& v) const {
        if (isZero() || v.isZero()) {
            return numeric_limits<T>::signaling_NaN();
        }

        return atan2<floating_point_type>(cross(v), dot(v));
    }
    floating_point_type arg(const Vector2D& a, const Vector2D& b) const { return (a - *this).arg(b - *this); }

    constexpr Vector2D lerp(const Vector2D& v, T f) const noexcept { return {x + (v.x - x) * f, y + (v.y - y) * f}; }

    constexpr friend Vector2D operator*(T s, const Vector2D& v) noexcept { return {s * v.x, s * v.y}; }
    friend istream& operator>>(istream& is, Vector2D& v) { return is >> v.x >> v.y; }
    friend ostream& operator<<(ostream& os, const Vector2D& v) { return os << "(" << v.x << ", " << v.y << ")"; }
};

template <typename T>
void argument_sort(vector<Vector2D<T>>& vec, const Vector2D<T>& center = Vector2D<T>(0, 0)) {
    auto orthant = [](const Vector2D<T>& v) {
        if (sgn(v.x) < 0 && sgn(v.y) < 0) return 0;
        if (sgn(v.x) >= 0 && sgn(v.y) < 0) return 1;
        if (sgn(v.x) == 0 && sgn(v.y) == 0) return 2;
        if (sgn(v.x) >= 0 && sgn(v.y) >= 0) return 3;
        return 4;
    };

    auto comp = [orthant, center](const Vector2D<T>& a, const Vector2D<T>& b) {
        const int o1 = orthant(a - center), o2 = orthant(b - center);
        if (o1 != o2) return o1 < o2;

        return (a - center).cross(b - center) > 0;
    };

    sort(vec.begin(), vec.end(), comp);
}

template <typename T>
vector<Vector2D<T>> convex_hull(vector<Vector2D<T>> points) {
    int n = points.size(), k = 0;
    vector<Vector2D<T>> res(n * 2);

    sort(points.begin(), points.end());
    points.erase(unique(points.begin(), points.end()), points.end());

    for (int i = 0; i < n; ++i) {
        while (k > 1 && sgn((res[k - 1] - res[k - 2]).cross(points[i] - res[k - 1])) <= 0) k--;
        res[k++] = points[i];
    }

    for (int i = n - 2, t = k; i >= 0; --i) {
        while (k > t && sgn((res[k - 1] - res[k - 2]).cross(points[i] - res[k - 1])) <= 0) k--;
        res[k++] = points[i];
    }

    res.resize(k - 1);
    return res;
}

/*
ABから見てBCは左に曲がるのなら +1
ABから見てBCは右に曲がるのなら -1
BACの順番で一直線上に並ぶなら +2
ABCの順番で一直線上に並ぶなら -2
CがAB上なら 0
*/
template <typename T>
constexpr int ccw(const Vector2D<T>& a, const Vector2D<T>& b, const Vector2D<T>& c) {
    const int res = sgn((b - a).cross(c - a));

    if (res != 0) return res;
    if (sgn((a - b).dot(c - a)) > 0) return +2;
    if (sgn((b - a).dot(c - b)) > 0) return -2;
    return 0;
}

using Vec2 = Vector2D<floating_point_type>;

struct Line {
    using value_type = Vec2::value_type;
    Vec2 begin, end;

    Line() = default;
    constexpr Line(const Vec2& begin, const Vec2& end) : begin(begin), end(end) {}
    constexpr Line(value_type sx, value_type sy, value_type gx, value_type gy) : begin(sx, sy), end(gx, gy) {}

    // ax + by + c = 0
    Line(value_type a, value_type b, value_type c) {
        assert(sgn(a) != 0 || sgn(b) != 0);

        if (sgn(b) == 0) {
            begin = Vec2(-c / a, 0.0);
            end = Vec2(-c / a, 1.0);
        } else {
            begin = Vec2(0, -c / b);
            end = Vec2(1.0, -(a + c) / b);
        }
    }

    constexpr Vec2 vector() const { return end - begin; }

    constexpr Line& reverse() {
        const Vec2 tmp = begin;
        begin = end;
        end = tmp;
        return *this;
    }
    constexpr Line reversed() const { return {end, begin}; }

    constexpr Line& moveBy(const Vec2& v) {
        begin += v;
        end += v;
        return *this;
    }
    constexpr Line movedBy(const Vec2& v) const { return {begin + v, end + v}; }

    constexpr bool isParallel(const Line& line) const { return sgn(vector().cross(line.vector())) == 0; }
    constexpr bool isOrthogonal(const Line& line) const { return sgn(vector().dot(line.vector())) == 0; }

    floating_point_type length() const { return vector().length(); }
    constexpr value_type lengthSq() const { return vector().lengthSq(); }

    floating_point_type distanceFrom(const Vec2& v) const { return fabs(vector().cross(v - begin)) / length(); }
    constexpr value_type distanceFromSq(const Vec2& v) const {
        const value_type d = vector().cross(v - begin);

        return d / lengthSq() * d;
    }

    optional<Vec2> intersectsAt(const Line& line) const {
        if (sgn(vector().cross(line.vector())) == 0) return nullopt;

        return begin + vector() * fabs((line.end - begin).cross(line.vector()) / vector().cross(line.vector()));
    }

    constexpr Vec2 projection(const Vec2& v) const { return begin + vector() * (v - begin).dot(vector()) / lengthSq(); }
    constexpr Vec2 reflection(const Vec2& v) const { return 2 * projection(v) - v; }

    // ax + by + c = 0
    constexpr tuple<value_type, value_type, value_type> generalForm() const {
        const Vec2 vec = vector();
        return {vec.y, -vec.x, end.cross(begin)};
    }

    friend istream& operator>>(istream& is, Line& rhs) { return is >> rhs.begin >> rhs.end; }
};

namespace segment {

using Segment = Line;

constexpr bool intersect(const Segment& a, const Segment& b) {
    return ccw(a.begin, a.end, b.begin) * ccw(a.begin, a.end, b.end) <= 0 && ccw(b.begin, b.end, a.begin) * ccw(b.begin, b.end, a.end) <= 0;
}

floating_point_type distance(const Segment& a, const Vec2& v) {
    if (sgn(a.vector().dot(v - a.begin)) < 0 || sgn((-a.vector()).dot(v - a.end)) < 0) {
        return min(v.distanceFrom(a.begin), v.distanceFrom(a.end));
    }
    return a.distanceFrom(v);
}

constexpr floating_point_type distanceSq(const Segment& a, const Vec2& v) {
    if (sgn(a.vector().dot(v - a.begin)) < 0 || sgn((-a.vector()).dot(v - a.end)) < 0) {
        return min(v.distanceFromSq(a.begin), v.distanceFromSq(a.end));
    }
    return a.distanceFromSq(v);
}

floating_point_type distance(const Segment& a, const Segment& b) {
    if (intersect(a, b)) return 0.0;

    return min({distance(a, b.begin), distance(a, b.end), distance(b, a.begin), distance(b, a.end)});
}
}  // namespace segment

struct Triangle {
    using value_type = Vec2::value_type;
    Vec2 p0, p1, p2;

    Triangle() = default;
    constexpr Triangle(const Vec2& p0, const Vec2& p1, const Vec2& p2) : p0(p0), p1(p1), p2(p2) {}

    constexpr Vec2& p(size_t index) { return (&p0)[index]; }
    constexpr const Vec2& p(size_t index) const { return (&p0)[index]; }

    constexpr Line side(size_t index) const {
        if (index == 0)
            return Line(p1, p2);
        else if (index == 1)
            return Line(p2, p0);
        else if (index == 2)
            return Line(p0, p1);
        else {
            throw std::out_of_range("Triangle::side() index out of range");
        }
    }

    floating_point_type angle(size_t index) const {
        const Vec2 vec[3] = {p(index), p((index + 1) % 3), p((index + 2) % 3)};

        const value_type res = vec[0].arg(vec[1], vec[2]);

        return fabs(res);
    }

    constexpr value_type area() const {
        const value_type res = (p1 - p0).cross(p2 - p0) / 2;
        return (0 < res ? res : -res);
    }

    constexpr Vec2 circumCenter() const {
        const value_type d0 = side(0).lengthSq(), d1 = side(1).lengthSq(), d2 = side(2).lengthSq(), t0 = d0 * (-d0 + d1 + d2),
                         t1 = d1 * (+d0 - d1 + d2), t2 = d2 * (+d0 + d1 - d2), t3 = t0 + t1 + t2;

        return t0 / t3 * p0 + t1 / t3 * p1 + t2 / t3 * p2;
    }

    Vec2 innerCenter() const {
        const value_type dist[3] = {side(0).length(), side(1).length(), side(2).length()};

        return (dist[0] * p0 + dist[1] * p1 + dist[2] * p2) / (dist[0] + dist[1] + dist[2]);
    }

    friend istream& operator>>(istream& is, Triangle& rhs) { return is >> rhs.p0 >> rhs.p1 >> rhs.p2; }
};

struct Circle {
    using value_type = Vec2::value_type;
    Vec2 center;
    value_type r;

    Circle() = default;
    explicit constexpr Circle(value_type r) : center(0.0, 0.0), r(r) {}
    constexpr Circle(value_type x, value_type y, value_type r) : center(x, y), r(r) {}
    constexpr Circle(const Vec2& center, value_type r) : center(center), r(r) {}

    constexpr bool intersects(const Line& line) const { return sgn(line.distanceFromSq(center) - r * r) <= 0; }

    constexpr bool intersects(const Circle& circle) const {
        const value_type d = center.distanceFromSq(circle.center);

        return sgn(square(r - circle.r) - d) <= 0 && sgn(d - square(r + circle.r)) <= 0;
    }

    constexpr bool circumcribes(const Circle& circle) const { return same(center.distanceFromSq(circle.center), square(r + circle.r)); }

    constexpr bool inscribes(const Circle& circle) const { return same(center.distanceFromSq(circle.center), square(r - circle.r)); }

    constexpr bool contains(const Circle& circle) const {
        return 0 < sgn(square(r - circle.r) - center.distanceFromSq(circle.center)) && 0 < sgn(r - circle.r);
    }

    constexpr value_type area() const { return Pi * r * r; }

    value_type commonArea(const Circle& circle) const {
        const value_type d_sq = center.distanceFromSq(circle.center);
        const value_type d = center.distanceFrom(circle.center);

        const value_type r1 = r;
        const value_type r2 = circle.r;

        if (sgn(d_sq - square(r1 + r2)) >= 0) return 0.0;
        if (sgn(d_sq - square(r1 - r2)) <= 0) return min(this->area(), circle.area());

        const value_type arg1 = acos(((r1 - r2) * (r1 + r2) + d_sq) / (2 * r1 * d));
        const value_type arg2 = acos(((r2 - r1) * (r2 + r1) + d_sq) / (2 * r2 * d));

        return r1 * r1 * (arg1 - sin(2 * arg1) / 2) + r2 * r2 * (arg2 - sin(2 * arg2) / 2);
    }

    constexpr Circle& moveBy(const Vec2& v) {
        center += v;
        return *this;
    }
    constexpr Circle movedBy(const Vec2& v) const { return {center + v, r}; }

    optional<vector<Vec2>> intersectsAt(const Line& line) const {
        if (!intersects(line)) return nullopt;

        vector<Vec2> res;

        const Vec2 v = line.projection(center);

        if (same(line.distanceFrom(center), r))
            res.emplace_back(v);
        else {
            value_type d = sqrt(r * r - (v - center).lengthSq());
            const Vec2 e = line.vector().normalized();

            res.emplace_back(v - d * e);
            res.emplace_back(v + d * e);
        }

        return res;
    }

    optional<vector<Vec2>> intersectsAt(const Circle& circle) const {
        if (!intersects(circle)) return nullopt;

        const value_type d = center.distanceFrom(circle.center), arg = (circle.center - center).arg(),
                         theta = acos((d * d + r * r - circle.r * circle.r) / (2 * d * r));

        vector<Vec2> res;
        res.emplace_back(center + r * Vec2(arg + theta));
        res.emplace_back(center + r * Vec2(arg - theta));

        if (res[0] > res[1]) swap(res[0], res[1]);

        return res;
    }

    optional<vector<Vec2>> tangentPointFrom(const Vec2& v) const {
        const value_type d = center.distanceFromSq(v);

        if (sgn(d - r * r) < 0) return nullopt;
        if (same(d, r * r)) return vector<Vec2>{v};

        const auto [x1, y1] = v - center;

        const auto& opt = Circle(r).intersectsAt(Line(x1, y1, -r * r));

        vector<Vec2> res = opt.value();

        for (Vec2& v : res) v += center;

        if (res[0] > res[1]) swap(res[0], res[1]);

        return res;
    }
    optional<vector<Vec2>> commonTangentPointFrom(const Circle& circle) const {
        const value_type r1 = r, r2 = circle.r;

        vector<Vec2> res;

        if (!same(r1, r2)) {
            const Vec2 p((r2 * center - r1 * circle.center) / (r2 - r1));

            const auto& opt = tangentPointFrom(p);

            if (opt.has_value()) {
                for (const Vec2& vec : opt.value()) {
                    res.emplace_back(vec);
                }
            }
        } else {
            const value_type theta = (circle.center - center).arg();

            res.emplace_back(center + r1 * Vec2(theta + 90_deg));
            res.emplace_back(center + r1 * Vec2(theta - 90_deg));
        }

        const Vec2 q((r2 * center + r1 * circle.center) / (r1 + r2));

        const auto& opt = tangentPointFrom(q);

        if (opt.has_value()) {
            for (const Vec2& vec : opt.value()) {
                res.emplace_back(vec);
            }
        }

        if (res.empty()) return nullopt;

        sort(res.begin(), res.end());

        return res;
    }

    friend istream& operator>>(istream& is, Circle& rhs) { return is >> rhs.center >> rhs.r; }
};

struct Polygon {
    using value_type = Vec2::value_type;
    int n;
    vector<Vec2> vertex;

    Polygon() = default;
    Polygon(int _n) : n(_n), vertex(_n) {}
    Polygon(const vector<Vec2>& vec) : n(static_cast<int>(vec.size())), vertex(vec) {}

    Line side(size_t index) const { return Line(vertex[index], vertex[(index + 1) % n]); }

    Polygon& moveBy(const Vec2& v) {
        for (Vec2& vec : vertex) vec += v;
        return *this;
    }
    Polygon movedBy(const Vec2& v) const {
        vector<Vec2> new_vertex;
        for (const Vec2& vec : vertex) new_vertex.emplace_back(vec + v);

        return Polygon(new_vertex);
    }

    bool isConvex() const {
        for (int i = 0; i < n; ++i) {
            if (ccw(vertex[i], vertex[(i + 1) % n], vertex[(i + 2) % n]) == -1) return false;
        }
        return true;
    }

    bool isOnEdge(const Vec2& v) const {
        for (int i = 0; i < n; ++i) {
            if (ccw(vertex[i], vertex[(i + 1) % n], v) == 0) return true;
        }
        return false;
    }

    bool intersects(const Vec2& v) const {
        floating_point_type sum = 0.0;

        for (int i = 0; i < n; ++i) {
            sum += v.arg(vertex[i], vertex[(i + 1) % n]);
        }

        return sgn(sum - 2.0 * Pi) == 0;
    }

    double area() const {
        value_type sum = 0.0;

        for (int i = 0; i < n; ++i) {
            sum += vertex[i].cross(vertex[i == n - 1 ? 0 : i + 1]);
        }

        return 0.5 * fabs(sum);
    }

    value_type commonArea(const Circle& circle) const {
        if (n < 3) return 0.0;

        if (!same(circle.center.x, 0.0) || !same(circle.center.y, 0.0)) {
            return (*this).movedBy(-circle.center).commonArea(Circle(circle.r));
        }

        auto cross_area = [&](auto self, Circle c, Vec2 a, Vec2 b) -> value_type {
            const Vec2 va = c.center - a, vb = c.center - b;

            value_type f = va.cross(vb), res = 0.0;

            if (same(f, 0.0)) return 0.0;
            if (sgn(max(va.length(), vb.length()) - c.r) <= 0) return f;

            const Line line(a, b);

            if (sgn(segment::distance(line, c.center) - c.r) >= 0) {
                return c.r * c.r * va.arg(vb);
            }

            const auto opt = c.intersectsAt(line);
            vector<Vec2> vec1 = opt.value();

            const vector<Vec2> vec2{a, vec1.front(), vec1.back(), b};

            for (int i = 0; i + 1 < vec2.size(); ++i) {
                res += self(self, c, vec2[i], vec2[i + 1]);
            }

            return res;
        };

        value_type sum = 0.0;

        for (int i = 0; i < n; ++i) {
            sum += cross_area(cross_area, circle, vertex[i], vertex[(i + 1) % n]);
        }

        sum *= 0.5;

        return fabs(sum);
    }

    Polygon convexHull() const { return convex_hull(vertex); }

    Polygon convexCut(const Line& line) const {
        assert(isConvex());

        vector<Vec2> res;

        for (int i = 0; i < n; ++i) {
            const Vec2 &now = vertex[i], &nxt = vertex[(i + 1) % n];

            if (ccw(line.begin, line.end, now) != -1) res.emplace_back(now);
            if (ccw(line.begin, line.end, now) * ccw(line.begin, line.end, nxt) < 0) {
                const auto& opt = Line(now, nxt).intersectsAt(line);
                if (opt.has_value()) res.emplace_back(opt.value());
            }
        }

        return Polygon(res);
    }

    value_type diameter() const {
        const auto convex = (isConvex() ? (*this) : convexHull()).vertex;

        const size_t n = convex.size();

        if (n == 2)
            return convex[0].distanceFrom(convex[1]);
        else {
            size_t i = 0, j = 0;

            for (size_t k = 0; k < n; ++k) {
                if (!(convex[i] < convex[k])) i = k;
                if (convex[j] < convex[k]) j = k;
            }

            value_type res = 0.0;

            const size_t si = i, sj = j;

            while (i != sj || j != si) {
                res = max(res, convex[i].distanceFrom(convex[j]));

                if ((convex[(i + 1) % n] - convex[i]).cross(convex[(j + 1) % n] - convex[j]) < 0) {
                    i = (i + 1) % n;
                } else
                    j = (j + 1) % n;
            }

            return res;
        }
    }

    friend istream& operator>>(istream& is, Polygon& rhs) {
        for (Vec2& e : rhs.vertex) is >> e;
        return is;
    }
};

}  // namespace geometry

using namespace geometry;

double perimeter(const vector<Vec2>& ps) {
    int n = ps.size();
    double res = 0.0;
    for (int i = 0; i < n; ++i) {
        res += ps[i].distanceFrom(ps[(i + 1) % n]);
    }
    return res;
}

void solve(int n, int k) {
    vector<Vec2> ps(n);
    cin >> ps;
    auto conv = convex_hull(ps);

    map<double, bool> vis;

    prique_inv<pair<double, vector<Vec2>>> que;
    que.emplace(perimeter(conv), conv);

    int cnt = 0;
    while (!que.empty()) {
        auto [len, p1] = que.top();
        que.pop();

        if (vis[len]) continue;
        vis[len] = true;

        cnt++;

        // cout << len << " " << p1 << endl;

        if (cnt == k) {
            cout << len << endl;
            return;
        }

        int n1 = p1.size();
        for (auto p_add : ps) {
            bool b = true;
            for (auto p : p1) {
                if (p_add == p) {
                    b = false;
                    break;
                }
            }
            if (!b) continue;

            rep(i, n1) {
                auto p2 = p1;
                p2.insert(p2.begin() + i, p_add);

                Polygon poly(p2);

                bool valid = true;
                for (auto p : ps) {
                    if (!poly.intersects(p) && !poly.isOnEdge(p)) {
                        valid = false;
                        break;
                    }
                }
                if (!valid) continue;

                rep(i1, n1 + 1) {
                    rep(j1, i1) {
                        if (j1 + 1 == i1 || (j1 == 0 && i1 == n1)) continue;
                        valid &= !segment::intersect(poly.side(i1), poly.side(j1));
                        if (!valid) {
                            // cout << p2 << endl;
                            break;
                        }
                    }
                }
                if (valid) {
                    // cout << p2 << endl;
                    double l1 = perimeter(p2);
                    que.emplace(l1, p2);
                }
            }
        }
    }
    cout << -1 << endl;
}
int main() {
    while (true) {
        int n, k;
        cin >> n >> k;
        if (n == 0) break;
        solve(n, k);
    }
}
accuracy: 1
time_ms: 120
memory_kb: 4228
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, a, b) for (int i = int(a); i < int(b); i++)
#define all(p) begin(p),end(p)
template<class T> ll sgn(T x) { return (x > 0) - (x < 0); }
template<class T> struct Point {
    using P = Point;
    T x, y;
    explicit Point(T x = 0, T y = 0) : x(x), y(y) {}
    bool operator<(P p) const { return tie(x, y) < tie(p.x, p.y); }
    bool operator==(P p) const { return tie(x, y) == tie(p.x, p.y); }
    P operator+(P p) const { return P(x + p.x, y + p.y); }
    P operator-(P p) const { return P(x - p.x, y - p.y); }
    P operator*(T d) const { return P(x * d, y * d); }
    P operator/(T d) const { return P(x / d, y / d); }
    T dot(P p) const { return x * p.x + y * p.y; }
    T cross(P p) const { return x * p.y - y * p.x; }
    T cross(P a, P b) const { return (a - *this).cross(b - *this); }
    T dist2() const { return x * x + y * y; }
    double dist() const { return sqrt(dist2()); }
    // angle to x-axis in interval [-pi, pi]
    double angle() const { return atan2(y, x); }
    P unit() const { return *this / dist(); }  // makes dist()=1
    P perp() const { return P(-y, x); }        // rotates +90 degrees
    P normal() const { return perp().unit(); }
    // returns point rotated 'a' radians ccw around the origin
    P rotate(double a) const {
        return P(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a));
    }
    friend ostream& operator<<(ostream& os, P p) {
        return os << "(" << p.x << "," << p.y << ")";
    }
};


using P = Point<ll>;

vector<P> convexHull(vector<P> pts){
    if (int(pts.size()) <= 1) return pts;
    sort(all(pts));
    vector<P> h(int(pts.size()) + 1);
    ll s = 0, t = 0;
    for (ll it = 2; it--; s = --t, reverse(all(pts))) for(P p : pts) {
        while (t >= s + 2 && h[t - 2].cross(h[t - 1], p) <= 0) t--;
        h[t++] = p;
    }
    return {h.begin(), h.begin() + t - (t == 2 && h[0] == h[1])};
}

template<class P> bool segInter(P a, P b, P c, P d) {
    if (a == c && b == d) return true;
    if (a == d && b == c) return true;
    auto oa = c.cross(d, a), ob = c.cross(d, b),
        oc = a.cross(b, c), od = a.cross(b, d);
    // Checks if intersection is single non-endpoint point.
    return sgn(oa) * sgn(ob) < 0 && sgn(oc) * sgn(od) < 0;
}

void solve(int N, int K){
    vector<P> p(N);
    rep(i, 0, N) cin >> p[i].x >> p[i].y;
    map<P, int> m;
    rep(i, 0, N) m[p[i]] = i;
    auto CH = convexHull(p);
    auto dist = [&](int a, int b) -> double {
        return sqrt(pow(p[a].x - p[b].x, 2) + pow(p[a].y - p[b].y, 2));
    };
    struct F{
        set<pair<int, int>> s;
        set<int> var;
        double val = 0;
    };
    vector<F> order(1);
    order.reserve(K + 1);
    rep(i, 0, CH.size()){
        int a = i, b = i - 1;
        if (b == -1) b = (int)(CH.size()) - 1;
        a = m[CH[a]];
        b = m[CH[b]];
        order[0].var.insert(a);
        if (a > b) swap(a, b);
        order[0].s.insert({a, b});
        order[0].val += dist(a, b);
    }
    rep(i, 0, K){
        // cout << i << endl;
        if (int(order.size()) == i){
            cout << "-1\n";
            return;
        }
        if (i == K - 1) break;
        for (auto x : order[i].s){
            auto base = order[i];
            base.s.erase(x);
            base.val -= dist(x.first, x.second);
            rep(j, 0, N){
                if (order[i].var.count(j)) continue;
                auto tmp = base;
                tmp.val += dist(j, x.first);
                tmp.val += dist(j, x.second);
                tmp.var.insert(j);
                vector<int> q = {x.first, j, x.second, x.first};
                rep(k, 0, 2){
                    tmp.s.insert({min(q[k], q[k + 1]), max(q[k], q[k + 1])});
                }
                bool ok = 1;
                for (auto y : base.s){
                    rep(k, 0, 2) if (segInter(p[y.first], p[y.second], p[q[k]], p[q[k + 1]])){
                        ok = 0;
                    }
                }
                rep(k, 0, N){
                    if (k == x.first) continue;
                    if (k == x.second) continue;
                    if (k == j) continue;
                    if (!ok) continue;
                    ok = 0;
                    rep(l, 0, 2){
                        if (sgn(p[q[l]].cross(p[q[l + 1]], p[k]))
                        != sgn(p[q[l + 1]].cross(p[q[l + 2]], p[k]))){
                            ok = 1;
                        }
                    }
                }
                for (auto z : order) if (z.s == tmp.s) ok = 0;
                if (!ok) continue;
                order.push_back(tmp);
                for (int j = (int)order.size() - 1; j - 1 > i; j--){
                    if (order[j - 1].val > order[j].val){
                        swap(order[j - 1], order[j]);
                    }
                    else break;
                }
                if (int(order.size()) == K + 1) order.pop_back();
            }
        }
    }
    cout << fixed << setprecision(20) << order.back().val << "\n";
}

int main(){
    int N, M;
    while (cin >> N >> M, N) solve(N, M);
}
accuracy: 1
time_ms: 80
memory_kb: 3616
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

template<class T>
bool chmax(T &a, const T &b) {if (a < b) {a = b; return 1;} return 0;}

using ll = long long;

/*-- geometry library --*/

using Real = long double;
using Point = complex<Real>;
const Real EPS = 1e-9, PI = acos(-1);

inline bool eq(Real a, Real b) {
  return fabs(b - a) < EPS;
}

ostream &operator<<(ostream &os, Point &p) {
  return os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

using Points = vector<Point>;
using Polygon = vector<Point>;

Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - imag(a) * real(b);
}

Real dot(const Point &a, const Point &b) {
  return real(a) * real(b) + imag(a) * imag(b);
}

namespace std {
bool operator<(const Point &a, const Point &b) {
  return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}
}  // namespace std

// 凸包
Polygon convex_hull(Polygon &p) {
  int n = (int)p.size(), k = 0;
  if (n <= 2) return p;
  sort(p.begin(), p.end());
  vector<Point> ch(2 * n);
  for (int i = 0; i < n; ch[k++] = p[i++]) {
    while (k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
  }
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
    while (k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
  }
  ch.resize(k - 1);
  return ch;
}

// 多角形と点の包含判定
enum { OUT, ON, IN };

int contains(const Polygon &Q, const Point &p) {
  bool in = false;
  for (int i = 0; i < Q.size(); i++) {
    Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
    if (a.imag() > b.imag()) swap(a, b);
    if (a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
    if (cross(a, b) == 0 && dot(a, b) <= 0) return ON;
  }
  return in ? IN : OUT;
}


bool is_end = false;

void solve()
{
    ll N, K; cin >> N >> K;
    if (N == 0 && K == 0)
    {
        is_end = true;
        return;
    }
    
    vector< Point > pos(N);
    for (int i = 0; i < N; ++i)
    {
        ll x, y; cin >> x >> y;
        pos[i] = Point(x, y);
    }
    
    Polygon conv = convex_hull(pos);
    vector<int> conv_ids;
    for (Point p : conv)
    {
        int tmp = 0;
        for (int i = 0; i < N; ++i)
        {
            if (p == pos[i]) tmp = i;
        }
        conv_ids.emplace_back(tmp);
    }
    
    priority_queue< pair<Real, vector<int>> > pq;
    set<vector<int>> used;
    auto calc_dist = [&](const vector<int> &vec) -> Real
    {
        Real ret = 0.0;
        int k = vec.size();
        for (int i = 0; i < k; ++i)
        {
            int id = vec[i];
            int nid = vec[(i+1)%k];
            ret += abs(pos[id] - pos[nid]);
        }
        return ret;
    };
    
    auto check_vec = [&](const vector<int> &vec) -> bool
    {
        int k = vec.size();
        Polygon poly(k);
        for (int i = 0; i < k; ++i) poly[i] = pos[vec[i]];
        for (int i = 0; i < N; ++i)
        {
            if (contains(poly, pos[i]) == OUT) return false;
        }
        return true;
    };
    
    pq.emplace(-calc_dist(conv_ids), conv_ids);
    used.insert(conv_ids);
    
    while (--K && pq.size())
    {
        auto [dist, vec] = pq.top();
        pq.pop();
        
        vector<bool> seen(N, false);
        for (auto v : vec) seen[v] = true;
        
        for (int nv = 0; nv < N; ++nv)
        {
            if (seen[nv]) continue;
            
            for (int i = 0; i < vec.size(); ++i)
            {
                vector<int> nvec = vec;
                nvec.insert(nvec.begin() + i + 1, nv);
                if (!check_vec(nvec)) continue;
                auto itr = used.find(nvec);
                if (itr != used.end()) continue;
                used.insert(nvec);
                
                pq.emplace(-calc_dist(nvec), nvec);
            }
        }
        
    }
    
    if (pq.size())
    {
        auto [res, vec] = pq.top();
        cout << fixed << setprecision(20);
        cout << -res << endl;
    }
    else
    {
        cout << -1 << endl;
    }
    
    
    return;
}

int main()
{
    while (!is_end)
    {
        solve();
    }
    
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3888
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;

// template {{{
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

#define  range(i, l, r) for (i64 i = (i64)(l); i < (i64)(r); (i) += 1)
#define rrange(i, l, r) for (i64 i = (i64)(r) - 1; i >= (i64)(l); (i) -= 1)

#define  whole(f, x, ...) ([&](decltype((x)) container) { return (f)(  begin(container),  end(container), ## __VA_ARGS__); })(x)
#define rwhole(f, x, ...) ([&](decltype((x)) container) { return (f)( rbegin(container), rend(container), ## __VA_ARGS__); })(x)

#define debug(x) cerr << "(" << __LINE__ << ")" << #x << ": " << (x) << endl

constexpr i32 inf   = 1001001001;
constexpr i64 infll = 1001001001001001001ll;

constexpr i32 dx[] = {0, -1, 1, 0, -1, 1, -1, 1}; 
constexpr i32 dy[] = {-1, 0, 0, 1, -1, -1, 1, 1};

struct IoSetup { IoSetup(i32 x = 15){ cin.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(x); cerr << fixed << setprecision(x); } } iosetup;

template <typename T = i64> T input() { T x; cin >> x; return x; }

template <typename T> ostream &operator<<(ostream &os, vector<T> &v) { range(i, 0, v.size()) { os << v[i] << (i + 1 != (int)v.size() ? " " : ""); } return os; } 
template <typename T> istream &operator>>(istream &is, vector<T> &v) { for (T &in : v) is >> in; return is; }

template <typename T1, typename T2> ostream &operator<<(ostream &os, pair<T1, T2> p) { os << "(" << p.first << ", " << p.second << ")"; return os; }
template <typename T1, typename T2> istream &operator>>(istream &is, pair<T1, T2> &p) { is >> p.first >> p.second; return is; }

template <typename T> vector<T> make_vector(size_t a, T b) { return vector<T>(a, b); }
template <typename... Ts> auto make_vector(size_t a, Ts... ts) { return vector<decltype(make_vector(ts...))>(a, make_vector(ts...)); }

template <typename T1, typename T2> inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }
template <typename T1, typename T2> inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }
// }}}

// Rolling Hash {{{
struct RollingHash {
  static const uint64_t mod = (1ull << 61ull) - 1;
  using uint128_t = __uint128_t;
  const uint64_t base;
  vector< uint64_t > power;

  static inline uint64_t add(uint64_t a, uint64_t b) {
    if((a += b) >= mod) a -= mod;
    return a;
  }

  static inline uint64_t mul(uint64_t a, uint64_t b) {
    uint128_t c = (uint128_t) a * b;
    return add(c >> 61, c & mod);
  }

  static inline uint64_t generate_base() {
    mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
    uniform_int_distribution< uint64_t > rand(1, RollingHash::mod - 1);
    return rand(mt);
  }

  inline void expand(size_t sz) {
    if(power.size() < sz + 1) {
      int pre_sz = (int) power.size();
      power.resize(sz + 1);
      for(int i = pre_sz - 1; i < (int)sz; i++) {
        power[i + 1] = mul(power[i], base);
      }
    }
  }

  explicit RollingHash(uint64_t base = generate_base()) : base(base), power{1} {}

  vector< uint64_t > build(const string &s) const {
    int sz = s.size();
    vector< uint64_t > hashed(sz + 1);
    for(int i = 0; i < sz; i++) {
      hashed[i + 1] = add(mul(hashed[i], base), s[i]);
    }
    return hashed;
  }

  template< typename T >
  vector< uint64_t > build(const vector< T > &s) const {
    int sz = s.size();
    vector< uint64_t > hashed(sz + 1);
    for(int i = 0; i < sz; i++) {
      hashed[i + 1] = add(mul(hashed[i], base), s[i]);
    }
    return hashed;
  }

  uint64_t query(const vector< uint64_t > &s, int l, int r) {
    expand(r - l);
    return add(s[r], mod - mul(s[l], power[r - l]));
  }

  uint64_t combine(uint64_t h1, uint64_t h2, size_t h2len) {
    expand(h2len);
    return add(mul(h1, power[h2len]), h2);
  }

  int lcp(const vector< uint64_t > &a, int l1, int r1, const vector< uint64_t > &b, int l2, int r2) {
    int len = min(r1 - l1, r2 - l2);
    int low = 0, high = len + 1;
    while(high - low > 1) {
      int mid = (low + high) / 2;
      if(query(a, l1, l1 + mid) == query(b, l2, l2 + mid)) low = mid;
      else high = mid;
    }
    return low;
  }
};
// }}}

// base
namespace geometry {
  using namespace std;
  using real_number = long double;

  const real_number PI = acosl(-1);

  inline static real_number &eps() {
    static real_number EPS = 1e-10;
    return EPS;
  }

  static void set_eps(real_number EPS) {
    eps() = EPS;
  }

  inline int sign(real_number r) {
    set_eps(1e-10);
    if (r < -eps()) return -1;
    if (r > +eps()) return +1;
    return 0;
  }

  inline bool equals(real_number r1, real_number r2) {
    return sign(r1 - r2) == 0;
  }
}

// point
namespace geometry {
  using point = complex< real_number >;
  using points = vector< point >;

  istream &operator>>(istream &is, point &p) {
    real_number x, y;
    is >> x >> y;
    p = point(x, y);
    return is;
  }

  ostream &operator<<(ostream &os, const point &p) {
    return os << p.real() << " " << p.imag();
  }

  point operator*(const point &p, const real_number &k) {
    return point(p.real() * k, p.imag() * k);
  }

  point rotate(const real_number &theta, const point &p) {
    return point(cos(theta) * p.real() + sin(-theta) * p.imag(),
                 sin(theta) * p.real() + cos(-theta) * p.imag());
  }

  bool equals(const point &a, const point &b) {
    return equals(a.real(), b.real()) and equals(a.imag(), b.imag());
  }
}

// polygon
namespace geometry {
  using polygon = vector< point >;
  using polygons = vector< polygon >;
}

namespace geometry {
  bool compare_x(const point &a, const point &b) {
    return !equals(a.real(), b.real()) ? a.real() < b.real() : a.imag() < b.imag();
  }

  bool compare_y(const point &a, const point &b) {
    return !equals(a.imag(), b.imag()) ? a.imag() < b.imag() : a.real() < b.real();
  }
}

// product
namespace geometry {
  real_number cross(const point &a, const point &b) {
    return a.real() * b.imag() - a.imag() * b.real();
  }

  real_number dot(const point &a, const point &b) {
    return a.real() * b.real() + a.imag() * b.imag();
  }
}

// convex_hull
namespace geometry {
  polygon convex_hull(points poly) {
    int n = poly.size(), k = 0;
    if (n <= 2) return poly;

    sort(poly.begin(), poly.end(), compare_x);
    polygon res(2 * n);

    auto check = [&](int i) {
      return sign(cross(res[k - 1] - res[k - 2], poly[i] - res[k - 1])) == -1;
    };

    for (int i = 0; i < n; res[k++] = poly[i++]) {
      while (k >= 2 and check(i)) --k;
    }

    for (int i = n - 2, t = k + 1; i >= 0; res[k++] = poly[i--]) {
      while (k >= t and check(i)) --k;
    }

    res.resize(k - 1);
    return res;
  }
}

// line 
namespace geometry {
  struct line {
    point a, b;

    line() = default;
    line(point a, point b) : a(a), b(b) {}
  };

  using lines = vector< line >;
}

// segment
namespace geometry {
  struct segment : line {
    segment() = default;
    using line::line;
  };

  using segments = vector< segment >;
}

// ccw
namespace geometry {
  constexpr int COUNTER_CLOCKWISE = +1;
  constexpr int CLOCKWISE         = -1;
  constexpr int ONLINE_BACK       = +2; // c-a-b
  constexpr int ONLINE_FRONT      = -2; // a-b-c
  constexpr int ON_SEGMENT        =  0; // a-c-b
  int ccw(const point &a, point b, point c) {
    b = b - a, c = c - a;
    if (sign(cross(b, c)) == +1) return COUNTER_CLOCKWISE;
    if (sign(cross(b, c)) == -1) return CLOCKWISE;
    if (sign(dot(b, c)) == -1) return ONLINE_BACK;
    if (norm(b) < norm(c)) return ONLINE_FRONT;
    return ON_SEGMENT;
  }
}

// intersect
namespace geometry {
  bool is_intersect(const segment &s1, const segment &s2) {
    return ccw(s1.a, s1.b, s2.a) * ccw(s1.a, s1.b, s2.b) <= 0 &&
           ccw(s2.a, s2.b, s1.a) * ccw(s2.a, s2.b, s1.b) <= 0;
  }
}

namespace geometry {
  /// O(N)
  /// 0 : point out the polygon
  /// 1 : point on the polygon edge
  /// 2 : point in the polygon
  constexpr int OUT     = 0;
  constexpr int ON_EDGE = 1;
  constexpr int IN      = 2;
  int contains(const polygon &poly, const point &p) {
    bool in = false;
    int n = poly.size();
    for (int i = 0; i < n; ++i) {
      int j = (i + 1 == n ? 0 : i + 1);
      point a = poly[i] - p, b = poly[j] - p;
      if (a.imag() > b.imag()) swap(a, b);
      if (a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
      if (sign(cross(a, b)) == 0 && sign(dot(a, b)) <= 0) {
        return ON_EDGE;
      }
    }

    return in ? IN : OUT;
  }
}
using namespace geometry;

RollingHash roll;

void solve(int n, int k) {
  points pts(n);
  cin >> pts;

  unordered_set< u64 > used;
  priority_queue< pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>> > pq;

  vector< vector<int> > vss;
  {
    auto convex_h = convex_hull(pts);

    vector< int > vs;
    for (auto &p : convex_h) {
      range(i, 0, n) {
        if (not equals(p, pts[i])) continue;
        vs.emplace_back(i);
      }
    }
    
    auto rh = roll.build(vs);
    u64 hash = roll.query(rh, 0, vs.size());

    double len = abs(pts[vs.front()] - pts[vs.back()]);
    range(i, 1, vs.size()) {
      len += abs(pts[vs[i]] - pts[vs[i - 1]]);
    }

    vss.emplace_back(vs);
    pq.emplace(len, 0);
    used.emplace(hash);
  }

  vector< vector<int> > ass;
  range(qi, 1, k + 1) {
    if (pq.empty()) {
      cout << -1 << endl;
      return;
    }
    if (qi == k) {
      cout << pq.top().first << endl;
      return;
    }

    auto [d, idx] = pq.top();
    pq.pop();

    auto as = vss[idx];
    ass.emplace_back(as);

    int m = as.size();
    set<int> st;
    for (auto &a : as) st.emplace(a);

    range(i, 0, n) {
      if (st.count(i)) continue;

      range(j, 0, as.size()) {
        // as の j 番目, j + 1 番目の間に pts[i] を挿入
        vector< int > vs;
        range(k, 0, j + 1) vs.emplace_back(as[k]);
        vs.emplace_back(i);
        range(k, j + 1, m) vs.emplace_back(as[k]);

        auto rh = roll.build(vs);
        u64 hash = roll.query(rh, 0, vs.size());
        if (used.count(hash)) {
          continue;
        }
        used.emplace(hash);

        segment s1(pts[i], pts[as[j]]);
        segment s2(pts[i], pts[as[(j + 1) % m]]);

        set<pair<int, int>> uku;
        uku.emplace((j - 1 + m) % m, j);
        uku.emplace(j, (j + 1) % m);
        uku.emplace((j + 1) % m, (j + 2) % m);
        // 交差判定
        bool f = false;
        range(k, 0, as.size()) {
          pair<int, int> si(k, (k + 1) % m);
          if (uku.count(si)) continue;

          segment s(pts[as[si.first]], pts[as[si.second]]);
          if (is_intersect(s, s1)) {
            f = true;
          }
          if (is_intersect(s, s2)) {
            f = true;
          }
        }

        polygon poly;
        for (auto i : vs) poly.emplace_back(pts[i]);
        for (auto &p : pts) if (contains(poly, p) == OUT) f = true;

        if (f) {
          continue; // can't insert
        }

        double len = abs(pts[vs.front()] - pts[vs.back()]);
        range(i, 1, vs.size()) {
          len += abs(pts[vs[i]] - pts[vs[i - 1]]);
        }

        pq.emplace(len, vss.size());
        vss.emplace_back(vs);
      }
    }
  }
}

signed main() {
  int n, k;
  
  while (cin >> n >> k, n) {
    solve(n, k);
  }
}
accuracy: 1
time_ms: 40
memory_kb: 3684
final_rank: 7

code_snippet: #line 1 "g.cpp"
#pragma region Macros
#include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

struct Setup {
    Setup() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
    }
} __Setup;

using ll = long long;
#define OVERLOAD3(_1, _2, _3, name, ...) name
#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
#define REP1(i, n) for(int i = 0; i < (n); i++)
#define REP2(i, a, b) for(int i = (a); i < int(b); i++)
#define REP(...) OVERLOAD3(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
const int INF = 1 << 30;
const ll LLINF = 1LL << 60;
constexpr int MOD = 1000000007;
constexpr int MOD2 = 998244353;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

void Case(int i) { cout << "Case #" << i << ": "; }
int popcount(int x) { return __builtin_popcount(x); }
ll popcount(ll x) { return __builtin_popcountll(x); }
#pragma endregion Macros

#line 1 "/home/siro53/kyo-pro/compro_library/geometry/geometry.hpp"
namespace geometry {
    // Point : 複素数型を位置ベクトルとして扱う
    // 実軸(real)をx軸、挙軸(imag)をy軸として見る
    using D = double;
    using Point = complex<D>;
    const D EPS = 1e-7;
    const D PI = acosl(-1);

    inline bool equal(const D &a, const D &b) { return fabs(a - b) < EPS; }

    // 単位ベクトル(unit vector)を求める
    Point unitVector(const Point &a) { return a / abs(a); }

    // 法線ベクトル(normal vector)を求める
    // 90度回転した単位ベクトルをかける
    // -90度がよければPoint(0, -1)をかける
    Point normalVector(const Point &a) { return a * Point(0, 1); }

    // 内積(dot product) : a・b = |a||b|cosΘ
    D dot(const Point &a, const Point &b) {
        return (a.real() * b.real() + a.imag() * b.imag());
    }

    // 外積(cross product) : a×b = |a||b|sinΘ
    D cross(const Point &a, const Point &b) {
        return (a.real() * b.imag() - a.imag() * b.real());
    }

    // 点pを反時計回りにtheta度回転
    // thetaはラジアン！！！
    Point rotate(const Point &p, const D &theta) {
        return Point(cos(theta) * p.real() - sin(theta) * p.imag(),
                     sin(theta) * p.real() + cos(theta) * p.imag());
    }

    // ラジアン->度
    D radianToDegree(const D &radian) { return radian * 180.0 / PI; }

    // 度->ラジアン
    D degreeToRadian(const D &degree) { return degree * PI / 180.0; }

    // 点の回転方向
    // 点a, b, cの位置関係について(aが基準点)
    int ccw(const Point &a, Point b, Point c) {
        b -= a, c -= a;
        // 点a, b, c が
        // 反時計回りの時、
        if(cross(b, c) > EPS) return 1;
        // 時計回りの時、
        if(cross(b, c) < -EPS) return -1;
        // c, a, bがこの順番で同一直線上にある時、
        if(dot(b, c) < 0) return 2;
        // a, b, cがこの順番で同一直線上にある場合、
        if(norm(b) < norm(c)) return -2;
        // cが線分ab上にある場合、
        return 0;
    }

    // Line : 直線を表す構造体
    // b - a で直線・線分を表せる
    struct Line {
        Point a, b;
        Line() = default;
        Line(Point a, Point b) : a(a), b(b) {}
        // Ax+By=C
        Line(D A, D B, D C) {
            if(equal(A, 0)) {
                a = Point(0, C / B), b = Point(1, C / B);
            } else if(equal(B, 0)) {
                b = Point(C / A, 0), b = Point(C / A, 1);
            } else {
                a = Point(0, C / B), b = Point(C / A, 0);
            }
        }
    };

    // Segment : 線分を表す構造体
    // Lineと同じ
    struct Segment : Line {
        Segment() = default;

        Segment(Point a, Point b) : Line(a, b) {}
    };

    // Circle : 円を表す構造体
    // pが中心の位置ベクトル、rは半径
    struct Circle {
        Point p;
        D r;

        Circle() = default;

        Circle(Point p, D r) : p(p), r(r) {}
    };

    // 2直線の直交判定 : a⊥b <=> dot(a, b) = 0
    bool isOrthogonal(const Line &a, const Line &b) {
        return equal(dot(a.b - a.a, b.b - b.a), 0);
    }
    // 2直線の平行判定 : a//b <=> cross(a, b) = 0
    bool isParallel(const Line &a, const Line &b) {
        return equal(cross(a.b - a.a, b.b - b.a), 0);
    }

    // 点cが直線ab上にあるか
    bool isPointOnLine(const Point &a, const Point &b, const Point &c) {
        return isParallel(Line(a, b), Line(a, c));
    }

    // 点cが"線分"ab上にあるか
    bool isPointOnSegment(const Point &a, const Point &b, const Point &c) {
        // |a-c| + |c-b| <= |a-b| なら線分上
        return (abs(a - c) + abs(c - b) < abs(a - b) + EPS);
    }

    // 直線lと点pの距離を求める
    D distanceBetweenLineAndPoint(const Line &l, const Point &p) {
        return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
    }

    // 線分lと点pの距離を求める
    // 定義：点pから「線分lのどこか」への最短距離
    D distanceBetweenSegmentAndPoint(const Segment &l, const Point &p) {
        if(dot(l.b - l.a, p - l.a) < EPS) return abs(p - l.a);
        if(dot(l.a - l.b, p - l.b) < EPS) return abs(p - l.b);
        return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
    }

    // 直線s, tの交点の計算
    Point crossPoint(const Line &s, const Line &t) {
        D d1 = cross(s.b - s.a, t.b - t.a);
        D d2 = cross(s.b - s.a, s.b - t.a);
        if(equal(abs(d1), 0) && equal(abs(d2), 0)) return t.a;
        return t.a + (t.b - t.a) * (d2 / d1);
    }

    // 線分s, tの交点の計算
    Point crossPoint(const Segment &s, const Segment &t) {
        return crossPoint(Line(s), Line(t));
    }

    // 線分sと線分tが交差しているかどうか
    // bound:線分の端点を含むか
    bool isIntersect(const Segment &s, const Segment &t, bool bound) {
        return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) < bound &&
               ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) < bound;
    }

    // 線分sとtの距離
    D distanceBetweenSegments(const Segment &s, const Segment &t) {
        if(isIntersect(s, t, 1)) return (D)(0);
        D ans = distanceBetweenSegmentAndPoint(s, t.a);
        chmin(ans, distanceBetweenSegmentAndPoint(s, t.b));
        chmin(ans, distanceBetweenSegmentAndPoint(t, s.a));
        chmin(ans, distanceBetweenSegmentAndPoint(t, s.b));
        return ans;
    }

    // 射影(projection)
    // 直線(線分)lに点pから引いた垂線の足を求める
    Point projection(const Line &l, const Point &p) {
        D t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
        return l.a + (l.a - l.b) * t;
    }

    Point projection(const Segment &l, const Point &p) {
        D t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
        return l.a + (l.a - l.b) * t;
    }

    // 反射(reflection)
    // 直線lを対称軸として点pと線対称の位置にある点を求める
    Point reflection(const Line &l, const Point &p) {
        return p + (projection(l, p) - p) * (D)2.0;
    }

    // 2つの円の交差判定
    // 返り値は共通接線の数
    int isIntersect(const Circle &c1, const Circle &c2) {
        D d = abs(c1.p - c2.p);
        // 2つの円が離れている場合
        if(d > c1.r + c2.r + EPS) return 4;
        // 外接している場合
        if(equal(d, c1.r + c2.r)) return 3;
        // 内接している場合
        if(equal(d, abs(c1.r - c2.r))) return 1;
        // 内包している場合
        if(d < abs(c1.r - c2.r) - EPS) return 0;
        return 2;
    }

    // 2つの円の交点
    vector<Point> crossPoint(const Circle &c1, const Circle &c2) {
        vector<Point> res;
        int mode = isIntersect(c1, c2);
        // 2つの中心の距離
        D d = abs(c1.p - c2.p);
        // 2円が離れている場合
        if(mode == 4) return res;
        // 1つの円がもう1つの円に内包されている場合
        if(mode == 0) return res;
        // 2円が外接する場合
        if(mode == 3) {
            D t = c1.r / (c1.r + c2.r);
            res.emplace_back(c1.p + (c2.p - c1.p) * t);
            return res;
        }
        // 内接している場合
        if(mode == 1) {
            if(c2.r < c1.r - EPS) {
                res.emplace_back(c1.p + (c2.p - c1.p) * (c1.r / d));
            } else {
                res.emplace_back(c2.p + (c1.p - c2.p) * (c2.r / d));
            }
            return res;
        }
        // 2円が重なる場合
        D rc1 = (c1.r * c1.r + d * d - c2.r * c2.r) / (2 * d);
        D rs1 = sqrt(c1.r * c1.r - rc1 * rc1);
        if(c1.r - abs(rc1) < EPS) rs1 = 0;
        Point e12 = (c2.p - c1.p) / abs(c2.p - c1.p);
        res.emplace_back(c1.p + rc1 * e12 + rs1 * e12 * Point(0, 1));
        res.emplace_back(c1.p + rc1 * e12 + rs1 * e12 * Point(0, -1));
        return res;
    }

    // 点pが円cの内部(円周上も含む)に入っているかどうか
    bool isInCircle(const Circle &c, const Point &p) {
        D d = abs(c.p - p);
        return (equal(d, c.r) || d < c.r - EPS);
    }

    // 円cと直線lの交点
    vector<Point> crossPoint(const Circle &c, const Line &l) {
        vector<Point> res;
        D d = distanceBetweenLineAndPoint(l, c.p);
        // 交点を持たない
        if(d > c.r + EPS) return res;
        // 接する
        Point h = projection(l, c.p);
        if(equal(d, c.r)) {
            res.emplace_back(h);
            return res;
        }
        Point e = unitVector(l.b - l.a);
        D ph = sqrt(c.r * c.r - d * d);
        res.emplace_back(h - e * ph);
        res.emplace_back(h + e * ph);
        return res;
    }

    // 点pを通る円cの接線
    // 2本あるので、接点のみを返す
    vector<Point> tangentToCircle(const Point &p, const Circle &c) {
        return crossPoint(c, Circle(p, sqrt(norm(c.p - p) - c.r * c.r)));
    }

    // 円の共通接線
    vector<Line> tangent(const Circle &a, const Circle &b) {
        vector<Line> ret;
        // 2円の中心間の距離
        D g = abs(a.p - b.p);
        // 円が内包されている場合
        if(equal(g, 0)) return ret;
        Point u = unitVector(b.p - a.p);
        Point v = rotate(u, PI / 2);
        for(int s : {-1, 1}) {
            D h = (a.r + b.r * s) / g;
            if(equal(h * h, 1)) {
                ret.emplace_back(a.p + (h > 0 ? u : -u) * a.r,
                                 a.p + (h > 0 ? u : -u) * a.r + v);

            } else if(1 - h * h > 0) {
                Point U = u * h, V = v * sqrt(1 - h * h);
                ret.emplace_back(a.p + (U + V) * a.r,
                                 b.p - (U + V) * (b.r * s));
                ret.emplace_back(a.p + (U - V) * a.r,
                                 b.p - (U - V) * (b.r * s));
            }
        }
        return ret;
    }

    // 多角形の面積を求める
    D PolygonArea(const vector<Point> &p) {
        D res = 0;
        int n = p.size();
        for(int i = 0; i < n - 1; i++) res += cross(p[i], p[i + 1]);
        res += cross(p[n - 1], p[0]);
        return res * 0.5;
    }

    // 凸多角形かどうか
    bool isConvex(const vector<Point> &p) {
        int n = p.size();
        int now, pre, nxt;
        for(int i = 0; i < n; i++) {
            pre = (i - 1 + n) % n;
            nxt = (i + 1) % n;
            now = i;
            if(ccw(p[pre], p[now], p[nxt]) == -1) return false;
        }
        return true;
    }

    // 凸包 O(NlogN)
    vector<Point> ConvexHull(vector<Point> p) {
        int n = (int)p.size(), k = 0;
        sort(ALL(p), [](const Point &a, const Point &b) {
            return (real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b));
        });
        vector<Point> ch(2 * n);
        // 一直線上の3点を含める -> (< -EPS)
        // 含め無い -> (< EPS)
        for(int i = 0; i < n; ch[k++] = p[i++]) { // lower
            while(k >= 2 &&
                  cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
                --k;
        }
        for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) { // upper
            while(k >= t &&
                  cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
                --k;
        }
        ch.resize(k - 1);
        return ch;
    }

    // 多角形gに点pが含まれているか?
    // 含まれる:2, 辺上にある:1, 含まれない:0
    int isContained(const vector<Point> &g, const Point &p) {
        bool in = false;
        int n = (int)g.size();
        for(int i = 0; i < n; i++) {
            Point a = g[i] - p, b = g[(i + 1) % n] - p;
            if(imag(a) > imag(b)) swap(a, b);
            if(imag(a) <= EPS && EPS < imag(b) && cross(a, b) < -EPS) in = !in;
            if(cross(a, b) == 0 && dot(a, b) <= 0) return 1;
        }
        return (in ? 2 : 0);
    }

} // namespace geometry
#line 76 "g.cpp"
using namespace geometry;

struct Data {
    D len;
    vector<Point> polygon;
    int mask;
    Data() {}
    Data(D len, vector<Point> p, int mask): len(len), polygon(p), mask(mask) {}
    bool operator<(const Data& d) const {
        return this->len > d.len;
    }
};

bool solve() {
    int N, K;
    cin >> N >> K;
    if(N == 0 and K == 0) return false;
    // debug(N, K);
    vector<Point> ps(N);
    map<pair<D, D>, int> ID;
    REP(i, N) {
        D x, y;
        cin >> x >> y;
        ps[i] = Point(x, y);
        ID[{x, y}] = i;
    }
    priority_queue<Data> que;
    auto compare = [](const vector<Point>& p1, const vector<Point>& p2) -> bool {
        if(p1.size() != p2.size()) return p1.size() < p2.size();
        REP(i, p1.size()) {
            if(p1[i].real() != p2[i].real()) {
                return p1[i].real() < p2[i].real();
            }
            if(p1[i].imag() != p2[i].imag()) {
                return p1[i].imag() < p2[i].imag();
            }
        }
        return false;
    };
    set<vector<Point>, decltype(compare)> se(compare);
    {
        auto p = ps;
        auto ch = ConvexHull(p);
        int sz = ch.size();
        D sum = 0.0;
        int mask = 0;
        REP(i, sz) {
            sum += abs(ch[i] - ch[i == sz-1 ? 0 : i+1]);
            mask |= (1 << ID.at({ch[i].real(), ch[i].imag()}));
        }
        // REP(i, sz) {
        //     debug(ch[i].real(), ch[i].imag());
        // }
        // debug(sum, mask);
        que.emplace(sum, ch, mask);
        se.emplace(ch);
    }

    REP(z, K) {
        if(que.empty()) {
            cout << "-1\n";
            return true;
        }
        auto [len, poly, mask] = que.top();
        int sz = poly.size();
        // debug(len, mask);
        // REP(i, sz) debug(poly[i].real(), poly[i].imag());
        que.pop();
        if(z == K-1) {
            cout << len << '\n';
            break;
        }
        REP(i, N) {
            if(mask >> i & 1) continue;
            // assert(isContained(poly, ps[i]) >= 1);
            REP(j, sz) {
                int now = j, nxt = (j == sz-1 ? 0 : j+1);
                Segment seg1(poly[now], ps[i]);
                Segment seg2(poly[nxt], ps[i]);
                bool ok = true;
                REP(k, sz) {
                    Segment L(poly[k], poly[(k == sz-1 ? 0 : k+1)]);
                    if(isIntersect(seg1, L, false) or isIntersect(seg2, L, false)) {
                        ok = false;
                        break;
                    }
                }
                auto npoly = poly;
                npoly.insert(npoly.begin() + j+1, ps[i]);
                REP(l, N) if(isContained(npoly, ps[l]) == 0) {
                    ok = false;
                    break;
                }
                if(ok) {
                    int nmask = mask | (1 << i);
                    D nlen = len + abs(poly[now] - ps[i]) + abs(poly[nxt] - ps[i]) - abs(poly[now] - poly[nxt]);
                    if(se.emplace(npoly).second) que.emplace(nlen, npoly, nmask);
                }
            }
        }
    }

    return true;
}

int main() {
    while(solve());
}
accuracy: 1
time_ms: 20
memory_kb: 4220
final_rank: 17

code_snippet: #line 1 "g.cpp"
#pragma region Macros
#include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

struct Setup {
    Setup() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
    }
} __Setup;

using ll = long long;
#define OVERLOAD3(_1, _2, _3, name, ...) name
#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
#define REP1(i, n) for(int i = 0; i < (n); i++)
#define REP2(i, a, b) for(int i = (a); i < int(b); i++)
#define REP(...) OVERLOAD3(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
const int INF = 1 << 30;
const ll LLINF = 1LL << 60;
constexpr int MOD = 1000000007;
constexpr int MOD2 = 998244353;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

void Case(int i) { cout << "Case #" << i << ": "; }
int popcount(int x) { return __builtin_popcount(x); }
ll popcount(ll x) { return __builtin_popcountll(x); }
#pragma endregion Macros

#line 1 "/home/siro53/kyo-pro/compro_library/geometry/geometry.hpp"
namespace geometry {
    // Point : 複素数型を位置ベクトルとして扱う
    // 実軸(real)をx軸、挙軸(imag)をy軸として見る
    using D = double;
    using Point = complex<D>;
    const D EPS = 1e-7;
    const D PI = acosl(-1);

    inline bool equal(const D &a, const D &b) { return fabs(a - b) < EPS; }

    // 単位ベクトル(unit vector)を求める
    Point unitVector(const Point &a) { return a / abs(a); }

    // 法線ベクトル(normal vector)を求める
    // 90度回転した単位ベクトルをかける
    // -90度がよければPoint(0, -1)をかける
    Point normalVector(const Point &a) { return a * Point(0, 1); }

    // 内積(dot product) : a・b = |a||b|cosΘ
    D dot(const Point &a, const Point &b) {
        return (a.real() * b.real() + a.imag() * b.imag());
    }

    // 外積(cross product) : a×b = |a||b|sinΘ
    D cross(const Point &a, const Point &b) {
        return (a.real() * b.imag() - a.imag() * b.real());
    }

    // 点pを反時計回りにtheta度回転
    // thetaはラジアン！！！
    Point rotate(const Point &p, const D &theta) {
        return Point(cos(theta) * p.real() - sin(theta) * p.imag(),
                     sin(theta) * p.real() + cos(theta) * p.imag());
    }

    // ラジアン->度
    D radianToDegree(const D &radian) { return radian * 180.0 / PI; }

    // 度->ラジアン
    D degreeToRadian(const D &degree) { return degree * PI / 180.0; }

    // 点の回転方向
    // 点a, b, cの位置関係について(aが基準点)
    int ccw(const Point &a, Point b, Point c) {
        b -= a, c -= a;
        // 点a, b, c が
        // 反時計回りの時、
        if(cross(b, c) > EPS) return 1;
        // 時計回りの時、
        if(cross(b, c) < -EPS) return -1;
        // c, a, bがこの順番で同一直線上にある時、
        if(dot(b, c) < 0) return 2;
        // a, b, cがこの順番で同一直線上にある場合、
        if(norm(b) < norm(c)) return -2;
        // cが線分ab上にある場合、
        return 0;
    }

    // Line : 直線を表す構造体
    // b - a で直線・線分を表せる
    struct Line {
        Point a, b;
        Line() = default;
        Line(Point a, Point b) : a(a), b(b) {}
        // Ax+By=C
        Line(D A, D B, D C) {
            if(equal(A, 0)) {
                a = Point(0, C / B), b = Point(1, C / B);
            } else if(equal(B, 0)) {
                b = Point(C / A, 0), b = Point(C / A, 1);
            } else {
                a = Point(0, C / B), b = Point(C / A, 0);
            }
        }
    };

    // Segment : 線分を表す構造体
    // Lineと同じ
    struct Segment : Line {
        Segment() = default;

        Segment(Point a, Point b) : Line(a, b) {}
    };

    // Circle : 円を表す構造体
    // pが中心の位置ベクトル、rは半径
    struct Circle {
        Point p;
        D r;

        Circle() = default;

        Circle(Point p, D r) : p(p), r(r) {}
    };

    // 2直線の直交判定 : a⊥b <=> dot(a, b) = 0
    bool isOrthogonal(const Line &a, const Line &b) {
        return equal(dot(a.b - a.a, b.b - b.a), 0);
    }
    // 2直線の平行判定 : a//b <=> cross(a, b) = 0
    bool isParallel(const Line &a, const Line &b) {
        return equal(cross(a.b - a.a, b.b - b.a), 0);
    }

    // 点cが直線ab上にあるか
    bool isPointOnLine(const Point &a, const Point &b, const Point &c) {
        return isParallel(Line(a, b), Line(a, c));
    }

    // 点cが"線分"ab上にあるか
    bool isPointOnSegment(const Point &a, const Point &b, const Point &c) {
        // |a-c| + |c-b| <= |a-b| なら線分上
        return (abs(a - c) + abs(c - b) < abs(a - b) + EPS);
    }

    // 直線lと点pの距離を求める
    D distanceBetweenLineAndPoint(const Line &l, const Point &p) {
        return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
    }

    // 線分lと点pの距離を求める
    // 定義：点pから「線分lのどこか」への最短距離
    D distanceBetweenSegmentAndPoint(const Segment &l, const Point &p) {
        if(dot(l.b - l.a, p - l.a) < EPS) return abs(p - l.a);
        if(dot(l.a - l.b, p - l.b) < EPS) return abs(p - l.b);
        return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
    }

    // 直線s, tの交点の計算
    Point crossPoint(const Line &s, const Line &t) {
        D d1 = cross(s.b - s.a, t.b - t.a);
        D d2 = cross(s.b - s.a, s.b - t.a);
        if(equal(abs(d1), 0) && equal(abs(d2), 0)) return t.a;
        return t.a + (t.b - t.a) * (d2 / d1);
    }

    // 線分s, tの交点の計算
    Point crossPoint(const Segment &s, const Segment &t) {
        return crossPoint(Line(s), Line(t));
    }

    // 線分sと線分tが交差しているかどうか
    // bound:線分の端点を含むか
    bool isIntersect(const Segment &s, const Segment &t, bool bound) {
        return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) < bound &&
               ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) < bound;
    }

    // 線分sとtの距離
    D distanceBetweenSegments(const Segment &s, const Segment &t) {
        if(isIntersect(s, t, 1)) return (D)(0);
        D ans = distanceBetweenSegmentAndPoint(s, t.a);
        chmin(ans, distanceBetweenSegmentAndPoint(s, t.b));
        chmin(ans, distanceBetweenSegmentAndPoint(t, s.a));
        chmin(ans, distanceBetweenSegmentAndPoint(t, s.b));
        return ans;
    }

    // 射影(projection)
    // 直線(線分)lに点pから引いた垂線の足を求める
    Point projection(const Line &l, const Point &p) {
        D t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
        return l.a + (l.a - l.b) * t;
    }

    Point projection(const Segment &l, const Point &p) {
        D t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
        return l.a + (l.a - l.b) * t;
    }

    // 反射(reflection)
    // 直線lを対称軸として点pと線対称の位置にある点を求める
    Point reflection(const Line &l, const Point &p) {
        return p + (projection(l, p) - p) * (D)2.0;
    }

    // 2つの円の交差判定
    // 返り値は共通接線の数
    int isIntersect(const Circle &c1, const Circle &c2) {
        D d = abs(c1.p - c2.p);
        // 2つの円が離れている場合
        if(d > c1.r + c2.r + EPS) return 4;
        // 外接している場合
        if(equal(d, c1.r + c2.r)) return 3;
        // 内接している場合
        if(equal(d, abs(c1.r - c2.r))) return 1;
        // 内包している場合
        if(d < abs(c1.r - c2.r) - EPS) return 0;
        return 2;
    }

    // 2つの円の交点
    vector<Point> crossPoint(const Circle &c1, const Circle &c2) {
        vector<Point> res;
        int mode = isIntersect(c1, c2);
        // 2つの中心の距離
        D d = abs(c1.p - c2.p);
        // 2円が離れている場合
        if(mode == 4) return res;
        // 1つの円がもう1つの円に内包されている場合
        if(mode == 0) return res;
        // 2円が外接する場合
        if(mode == 3) {
            D t = c1.r / (c1.r + c2.r);
            res.emplace_back(c1.p + (c2.p - c1.p) * t);
            return res;
        }
        // 内接している場合
        if(mode == 1) {
            if(c2.r < c1.r - EPS) {
                res.emplace_back(c1.p + (c2.p - c1.p) * (c1.r / d));
            } else {
                res.emplace_back(c2.p + (c1.p - c2.p) * (c2.r / d));
            }
            return res;
        }
        // 2円が重なる場合
        D rc1 = (c1.r * c1.r + d * d - c2.r * c2.r) / (2 * d);
        D rs1 = sqrt(c1.r * c1.r - rc1 * rc1);
        if(c1.r - abs(rc1) < EPS) rs1 = 0;
        Point e12 = (c2.p - c1.p) / abs(c2.p - c1.p);
        res.emplace_back(c1.p + rc1 * e12 + rs1 * e12 * Point(0, 1));
        res.emplace_back(c1.p + rc1 * e12 + rs1 * e12 * Point(0, -1));
        return res;
    }

    // 点pが円cの内部(円周上も含む)に入っているかどうか
    bool isInCircle(const Circle &c, const Point &p) {
        D d = abs(c.p - p);
        return (equal(d, c.r) || d < c.r - EPS);
    }

    // 円cと直線lの交点
    vector<Point> crossPoint(const Circle &c, const Line &l) {
        vector<Point> res;
        D d = distanceBetweenLineAndPoint(l, c.p);
        // 交点を持たない
        if(d > c.r + EPS) return res;
        // 接する
        Point h = projection(l, c.p);
        if(equal(d, c.r)) {
            res.emplace_back(h);
            return res;
        }
        Point e = unitVector(l.b - l.a);
        D ph = sqrt(c.r * c.r - d * d);
        res.emplace_back(h - e * ph);
        res.emplace_back(h + e * ph);
        return res;
    }

    // 点pを通る円cの接線
    // 2本あるので、接点のみを返す
    vector<Point> tangentToCircle(const Point &p, const Circle &c) {
        return crossPoint(c, Circle(p, sqrt(norm(c.p - p) - c.r * c.r)));
    }

    // 円の共通接線
    vector<Line> tangent(const Circle &a, const Circle &b) {
        vector<Line> ret;
        // 2円の中心間の距離
        D g = abs(a.p - b.p);
        // 円が内包されている場合
        if(equal(g, 0)) return ret;
        Point u = unitVector(b.p - a.p);
        Point v = rotate(u, PI / 2);
        for(int s : {-1, 1}) {
            D h = (a.r + b.r * s) / g;
            if(equal(h * h, 1)) {
                ret.emplace_back(a.p + (h > 0 ? u : -u) * a.r,
                                 a.p + (h > 0 ? u : -u) * a.r + v);

            } else if(1 - h * h > 0) {
                Point U = u * h, V = v * sqrt(1 - h * h);
                ret.emplace_back(a.p + (U + V) * a.r,
                                 b.p - (U + V) * (b.r * s));
                ret.emplace_back(a.p + (U - V) * a.r,
                                 b.p - (U - V) * (b.r * s));
            }
        }
        return ret;
    }

    // 多角形の面積を求める
    D PolygonArea(const vector<Point> &p) {
        D res = 0;
        int n = p.size();
        for(int i = 0; i < n - 1; i++) res += cross(p[i], p[i + 1]);
        res += cross(p[n - 1], p[0]);
        return res * 0.5;
    }

    // 凸多角形かどうか
    bool isConvex(const vector<Point> &p) {
        int n = p.size();
        int now, pre, nxt;
        for(int i = 0; i < n; i++) {
            pre = (i - 1 + n) % n;
            nxt = (i + 1) % n;
            now = i;
            if(ccw(p[pre], p[now], p[nxt]) == -1) return false;
        }
        return true;
    }

    // 凸包 O(NlogN)
    vector<Point> ConvexHull(vector<Point> &p) {
        int n = (int)p.size(), k = 0;
        sort(ALL(p), [](const Point &a, const Point &b) {
            return (real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b));
        });
        vector<Point> ch(2 * n);
        // 一直線上の3点を含める -> (< -EPS)
        // 含め無い -> (< EPS)
        for(int i = 0; i < n; ch[k++] = p[i++]) { // lower
            while(k >= 2 &&
                  cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
                --k;
        }
        for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) { // upper
            while(k >= t &&
                  cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS)
                --k;
        }
        ch.resize(k - 1);
        return ch;
    }

    // 多角形gに点pが含まれているか?
    // 含まれる:2, 辺上にある:1, 含まれない:0
    int isContained(const vector<Point> &g, const Point &p) {
        bool in = false;
        int n = (int)g.size();
        for(int i = 0; i < n; i++) {
            Point a = g[i] - p, b = g[(i + 1) % n] - p;
            if(imag(a) > imag(b)) swap(a, b);
            if(imag(a) <= EPS && EPS < imag(b) && cross(a, b) < -EPS) in = !in;
            if(cross(a, b) == 0 && dot(a, b) <= 0) return 1;
        }
        return (in ? 2 : 0);
    }

} // namespace geometry
#line 76 "g.cpp"
using namespace geometry;

struct Data {
    D len;
    vector<Point> polygon;
    int mask;
    Data() {}
    Data(D len, vector<Point> p, int mask): len(len), polygon(p), mask(mask) {}
    bool operator<(const Data& d) const {
        return this->len > d.len;
    }
};

bool solve() {
    int N, K;
    cin >> N >> K;
    if(N == 0 and K == 0) return false;
    // debug(N, K);
    vector<Point> ps(N);
    map<pair<D, D>, int> ID;
    REP(i, N) {
        D x, y;
        cin >> x >> y;
        ps[i] = Point(x, y);
        ID[{x, y}] = i;
    }
    priority_queue<Data> que;
    auto compare = [](const vector<Point>& p1, const vector<Point>& p2) -> bool {
        if(p1.size() != p2.size()) return p1.size() < p2.size();
        REP(i, p1.size()) {
            if(p1[i].real() != p2[i].real()) {
                return p1[i].real() < p2[i].real();
            }
            if(p1[i].imag() != p2[i].imag()) {
                return p1[i].imag() < p2[i].imag();
            }
        }
        return false;
    };
    set<vector<Point>, decltype(compare)> se(compare);
    {
        auto p = ps;
        auto ch = ConvexHull(p);
        int sz = ch.size();
        D sum = 0.0;
        int mask = 0;
        REP(i, sz) {
            sum += abs(ch[i] - ch[i == sz-1 ? 0 : i+1]);
            mask |= (1 << ID.at({ch[i].real(), ch[i].imag()}));
        }
        // REP(i, sz) {
        //     debug(ch[i].real(), ch[i].imag());
        // }
        // debug(sum, mask);
        que.emplace(sum, ch, mask);
        se.emplace(ch);
    }

    REP(z, K) {
        if(que.empty()) {
            cout << "-1\n";
            return true;
        }
        auto [len, poly, mask] = que.top();
        int sz = poly.size();
        // debug(len, mask);
        // REP(i, sz) debug(poly[i].real(), poly[i].imag());
        que.pop();
        if(z == K-1) {
            cout << len << '\n';
            break;
        }
        REP(i, N) {
            if(mask >> i & 1) continue;
            // assert(isContained(poly, ps[i]) >= 1);
            REP(j, sz) {
                int now = j, nxt = (j == sz-1 ? 0 : j+1);
                Segment seg1(poly[now], ps[i]);
                Segment seg2(poly[nxt], ps[i]);
                bool ok = true;
                REP(k, sz) {
                    Segment L(poly[k], poly[(k == sz-1 ? 0 : k+1)]);
                    if(isIntersect(seg1, L, false) or isIntersect(seg2, L, false)) {
                        ok = false;
                        break;
                    }
                }
                auto npoly = poly;
                npoly.insert(npoly.begin() + j+1, ps[i]);
                REP(l, N) if(isContained(npoly, ps[l]) == 0) {
                    ok = false;
                    break;
                }
                if(ok) {
                    int nmask = mask | (1 << i);
                    D nlen = len + abs(poly[now] - ps[i]) + abs(poly[nxt] - ps[i]) - abs(poly[now] - poly[nxt]);
                    if(se.emplace(npoly).second) que.emplace(nlen, npoly, nmask);
                }
            }
        }
    }

    return true;
}

int main() {
    while(solve());
}
accuracy: 1
time_ms: 30
memory_kb: 4152
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, x) for(int i = 0; i < (x); i++)
#define all(x) (x).begin(), (x).end()

using Real = double;
using Point = complex<Real>;
const Real EPS = 1e-8, PI = acos(-1);

std::istream &operator>>(istream &is, Point &p) {
	Real a, b;
	is >> a >> b;
	p = Point(a, b);
	return is;
}

namespace std {
bool operator<(const Point &a, const Point &b) {
	return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}
}  // namespace std

using Polygon = vector<Point>;

void p_sort(Polygon &p) {
	vector<pair<Real, Point>> v;
	for(auto g : p) {
		Real theta = arg(g);
		v.emplace_back(theta, g);
	}
	sort(all(v));
	for(int i = 0; i < int(p.size()); i++) {
		p[i] = v[i].second;
	}
	return;
}

Real cross(const Point &a, const Point &b) {
	return real(a) * imag(b) - imag(a) * real(b);
}

Real distance(const Point &a, const Point &b) {
	return abs(a - b);
}

Polygon convex_hull(Polygon &p) {
	int n = p.size(), k = 0;
	if(n <= 2) return p;
	sort(p.begin(), p.end());
	Polygon ch(2 * n);
	for(int i = 0; i < n; ch[k++] = p[i++]) {
		while(k >= 2 and cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
	}
	for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
		while(k >= t and cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
	}
	ch.resize(k - 1);
	return ch;
}

inline bool eq(Real a, Real b) { return fabs(b - a) < EPS; }

Real dot(const Point &a, const Point &b) {
	return real(a) * real(b) + imag(a) * imag(b);
}

//onなら0 inなら1 outなら2
int contains(const Polygon &Q, const Point &p) {
	bool in = false;
	rep(i, Q.size()) {
		Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
		if(a.imag() > b.imag()) swap(a, b);
		if(a.imag() <= 0 and 0 < b.imag() and cross(a, b) < 0) in = !in;
		if(eq(cross(a, b), 0) and dot(a, b) <= 0) return 0;
	}
	return in ? 1 : 2;
}

Real syuutyou(Polygon &p) {
	// cout << "P!!\n";
	// for(auto q : p) {
	// 	cout << real(q) << " " << imag(q) << endl;
	// }
	Real lt = 0;
	rep(i, p.size() - 1) {
		lt += distance(p[i], p[i + 1]);
	}
	lt += distance(p[0], p.back());
	//cout << lt << endl;
	return lt;
}

int ccw(const Point &a, Point b, Point c) {
	b = b - a, c = c - a;
	if(cross(b, c) > EPS) return +1;            // "COUNTER_CLOCKWISE"
	if(cross(b, c) < -EPS) return -1;           // "CLOCKWISE"
	if(dot(b, c) < 0) return +2;                // "ONLINE_BACK"
	if(std::norm(b) < std::norm(c)) return -2;  // "ONLINE_FRONT"
	return 0;                                   // "ON_SEGMENT"
}

struct Line {
	Point a, b;

	Line() = default;

	Line(Point a, Point b) : a(a), b(b) {}

	Line(Real A, Real B, Real C)  // Ax + By = C
	{
		if(eq(A, 0))
			a = Point(0, C / B), b = Point(1, C / B);
		else if(eq(B, 0))
			b = Point(C / A, 0), b = Point(C / A, 1);
		else
			a = Point(0, C / B), b = Point(C / A, 0);
	}

	friend std::ostream &operator<<(std::ostream &os, Line &p) {
		return os << p.a << " to " << p.b;
	}

	friend std::istream &operator>>(std::istream &is, Line &a) {
		return is >> a.a >> a.b;
	}
};

struct Segment : Line {
	Segment() = default;

	Segment(Point a, Point b) : Line(a, b) {}
};

bool intersect(const Segment &s, const Segment &t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 and ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

std::ostream &operator<<(std::ostream &os, Point &p) {
	return os << std::fixed << std::setprecision(10) << p.real() << " " << p.imag();
}

int n, k;
int main() {
	cout << fixed << setprecision(10);
	while(cin >> n >> k, n + k) {
		set<Polygon> st;
		bool fin = 0;
		Real res;
		Polygon p(n);
		rep(i, n) {
			cin >> p[i];
		}
		auto q = convex_hull(p);

		vector<Polygon> befs = {q};
		st.insert(q);
		rep(i, k - 1) {
			Real len = 1 << 30;
			Polygon tmp = {};
			for(const auto bef : befs) {
				for(auto u : p) {
					if(contains(bef, u) == 1) {
						for(int i = 0; i < bef.size() - 1; i++) {
							Polygon tri = {bef[i], bef[i + 1], u};

							bool ok = 1;
							for(auto v : p) {
								ok &= contains(tri, v) != 1;
							}
							if(ok) {
								auto p1 = bef;
								p1.insert(p1.begin() + i + 1, u);
								bool out = 0;
								for(int j = 0; j < p1.size(); j++) {
									for(int k = j; k < p1.size(); k++) {
										auto a = p1[j];
										auto b = p1[j + 1];
										auto c = p1[k];
										auto d = p1[(k + 1) == p1.size() ? 0 : k + 1];
										if(b == c or b == d or a == c or a == d) continue;
										Segment l(a, b);
										Segment r(c, d);
										if(intersect(l, r)) {
											out = 1;
										}
									}
								}
								Real lt = syuutyou(p1);
								if(!out and lt < len and !st.count(p1)) {
									len = lt;
									//cout << "len " << len << endl;
									tmp = p1;
								}
							}
						}
						Polygon tri = {bef[0], bef.back(), u};
						bool ok = 1;
						for(auto v : p) {
							ok &= contains(tri, v) != 1;
						}
						if(ok) {
							auto p1 = bef;
							p1.insert(p1.begin(), u);
							bool out = 0;
							for(int j = 0; j < p1.size(); j++) {
								for(int k = j; k < p1.size(); k++) {
									auto a = p1[j];
									auto b = p1[j + 1];
									auto c = p1[k];
									auto d = p1[(k + 1) == p1.size() ? 0 : k + 1];
									if(b == c or b == d or a == c or a == d) continue;
									Segment l(a, b);
									Segment r(c, d);
									if(intersect(l, r)) {
										out = 1;
									}
								}
							}
							Real lt = syuutyou(p1);
							if(!out and lt < len and !st.count(p1)) {
								len = lt;
								//cout << "len " << len << endl;
								tmp = p1;
							}
						}
					}
				}
			}
			if(tmp.size()) {
				befs.push_back(tmp);
				st.insert(tmp);
			} else {
				cout << -1 << endl;
				fin = 1;
				break;
			}
		}
		// for(auto &v : befs) {
		// 	cout << syuutyou(v) << " " << v.size() << endl;
		// 	for(auto u : v) cout << u << endl;
		// }
		if(!fin) cout << syuutyou(befs.back()) << endl;
	}
}
accuracy: 1
time_ms: 90
memory_kb: 3612
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define rep(i, x) for(int i = 0; i < (x); i++)
#define all(x) (x).begin(), (x).end()

using Real = double;
using Point = complex<Real>;
const Real EPS = 1e-8, PI = acos(-1);

std::istream &operator>>(istream &is, Point &p) {
	Real a, b;
	is >> a >> b;
	p = Point(a, b);
	return is;
}

namespace std {
bool operator<(const Point &a, const Point &b) {
	return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}
}  // namespace std

using Polygon = vector<Point>;

void p_sort(Polygon &p) {
	vector<pair<Real, Point>> v;
	for(auto g : p) {
		Real theta = arg(g);
		v.emplace_back(theta, g);
	}
	sort(all(v));
	for(int i = 0; i < int(p.size()); i++) {
		p[i] = v[i].second;
	}
	return;
}

Real cross(const Point &a, const Point &b) {
	return real(a) * imag(b) - imag(a) * real(b);
}

Real distance(const Point &a, const Point &b) {
	return abs(a - b);
}

Polygon convex_hull(Polygon &p) {
	int n = p.size(), k = 0;
	if(n <= 2) return p;
	sort(p.begin(), p.end());
	Polygon ch(2 * n);
	for(int i = 0; i < n; ch[k++] = p[i++]) {
		while(k >= 2 and cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
	}
	for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
		while(k >= t and cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < EPS) --k;
	}
	ch.resize(k - 1);
	return ch;
}

inline bool eq(Real a, Real b) { return fabs(b - a) < EPS; }

Real dot(const Point &a, const Point &b) {
	return real(a) * real(b) + imag(a) * imag(b);
}

//onなら0 inなら1 outなら2
int contains(const Polygon &Q, const Point &p) {
	bool in = false;
	rep(i, Q.size()) {
		Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
		if(a.imag() > b.imag()) swap(a, b);
		if(a.imag() <= 0 and 0 < b.imag() and cross(a, b) < 0) in = !in;
		if(eq(cross(a, b), 0) and dot(a, b) <= 0) return 0;
	}
	return in ? 1 : 2;
}

Real syuutyou(Polygon &p) {
	// cout << "P!!\n";
	// for(auto q : p) {
	// 	cout << real(q) << " " << imag(q) << endl;
	// }
	Real lt = 0;
	rep(i, p.size() - 1) {
		lt += distance(p[i], p[i + 1]);
	}
	lt += distance(p[0], p.back());
	//cout << lt << endl;
	return lt;
}

int ccw(const Point &a, Point b, Point c) {
	b = b - a, c = c - a;
	if(cross(b, c) > EPS) return +1;            // "COUNTER_CLOCKWISE"
	if(cross(b, c) < -EPS) return -1;           // "CLOCKWISE"
	if(dot(b, c) < 0) return +2;                // "ONLINE_BACK"
	if(std::norm(b) < std::norm(c)) return -2;  // "ONLINE_FRONT"
	return 0;                                   // "ON_SEGMENT"
}

struct Line {
	Point a, b;

	Line() = default;

	Line(Point a, Point b) : a(a), b(b) {}

	Line(Real A, Real B, Real C)  // Ax + By = C
	{
		if(eq(A, 0))
			a = Point(0, C / B), b = Point(1, C / B);
		else if(eq(B, 0))
			b = Point(C / A, 0), b = Point(C / A, 1);
		else
			a = Point(0, C / B), b = Point(C / A, 0);
	}

	friend std::ostream &operator<<(std::ostream &os, Line &p) {
		return os << p.a << " to " << p.b;
	}

	friend std::istream &operator>>(std::istream &is, Line &a) {
		return is >> a.a >> a.b;
	}
};

struct Segment : Line {
	Segment() = default;

	Segment(Point a, Point b) : Line(a, b) {}
};

bool intersect(const Segment &s, const Segment &t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 and ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

std::ostream &operator<<(std::ostream &os, Point &p) {
	return os << std::fixed << std::setprecision(10) << p.real() << " " << p.imag();
}

int n, k;
int main() {
	cout << fixed << setprecision(10);
	while(cin >> n >> k, n + k) {
		set<Polygon> st;
		bool fin = 0;
		Real res;
		Polygon p(n);
		rep(i, n) {
			cin >> p[i];
		}
		auto q = convex_hull(p);

		vector<Polygon> befs = {q};
		st.insert(q);
		rep(i, k - 1) {
			Real len = 1 << 30;
			Polygon tmp = {};
			for(const auto bef : befs) {
				for(auto u : p) {
					if(contains(bef, u) == 1) {
						for(int i = 0; i < bef.size() - 1; i++) {
							Polygon tri = {bef[i], bef[i + 1], u};

							bool ok = 1;
							for(auto v : p) {
								ok &= contains(tri, v) != 1;
							}
							if(ok) {
								auto p1 = bef;
								p1.insert(p1.begin() + i + 1, u);
								bool out = 0;
								for(int j = 0; j < p1.size(); j++) {
									for(int k = j; k < p1.size(); k++) {
										auto a = p1[j];
										auto b = p1[j + 1];
										auto c = p1[k];
										auto d = p1[(k + 1) == p1.size() ? 0 : k + 1];
										if(b == c or b == d or a == c or a == d) continue;
										Segment l(a, b);
										Segment r(c, d);
										if(intersect(l, r)) {
											out = 1;
										}
									}
								}
								Real lt = syuutyou(p1);
								if(!out and lt < len and !st.count(p1)) {
									len = lt;
									//cout << "len " << len << endl;
									tmp = p1;
								}
							}
						}
						Polygon tri = {bef[0], bef.back(), u};
						bool ok = 1;
						for(auto v : p) {
							ok &= contains(tri, v) != 1;
						}
						if(ok) {
							auto p1 = bef;
							p1.insert(p1.begin(), u);
							bool out = 0;
							for(int j = 0; j < p1.size(); j++) {
								for(int k = j; k < p1.size(); k++) {
									auto a = p1[j];
									auto b = p1[j + 1];
									auto c = p1[k];
									auto d = p1[(k + 1) == p1.size() ? 0 : k + 1];
									if(b == c or b == d or a == c or a == d) continue;
									Segment l(a, b);
									Segment r(c, d);
									if(intersect(l, r)) {
										out = 1;
									}
								}
							}
							Real lt = syuutyou(p1);
							if(!out and lt < len and !st.count(p1)) {
								len = lt;
								//cout << "len " << len << endl;
								tmp = p1;
							}
						}
					}
				}
			}
			if(tmp.size()) {
				befs.push_back(tmp);
				st.insert(tmp);
			} else {
				cout << -1 << endl;
				fin = 1;
				break;
			}
		}
		// for(auto &v : befs) {
		// 	cout << syuutyou(v) << " " << v.size() << endl;
		// 	for(auto u : v) cout << u << endl;
		// }
		if(!fin) cout << syuutyou(befs.back()) << endl;
	}
}
accuracy: 1
time_ms: 90
memory_kb: 3540
final_rank: 4

code_snippet: #include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <queue>
#include <set>
using namespace std;

const double EPS = 1e-8;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)

struct P{
    double X;
    double Y;
    P(double x=0.0, double y=0.0): X(x),Y(y){}

    inline const P inv() const { return P(X/(X*X+Y*Y), -Y/(X*X+Y*Y)); }
    inline const P operator -() const { return P(-X, -Y); }
    inline const P operator +(const P& a) const { return P(X+a.X, Y+a.Y); }
    inline const P operator -(const P& a) const { return P(X-a.X, Y-a.Y); }
    inline const P operator *(const P& a) const { return P(X*a.X -Y*a.Y, X*a.Y +Y*a.X); }
    inline const P operator /(const P& a) const { return *this *a.inv(); }
    inline const P operator *(const double& c) const { return P(c*X, c*Y); }
    inline const P operator /(const double& c) const { return P(X/c, Y/c); }

    inline P& operator +=(const P& a){ X+=a.X; Y+=a.Y; return *this; }
    inline P& operator -=(const P& a){ X-=a.X; Y-=a.Y; return *this; }
    inline P& operator *=(const P& a){ double nX=X*a.X-Y*a.Y; Y=X*a.Y+Y*a.X; X=nX; return *this; }
    inline P& operator /=(const P& a){ double d=a.X*a.X+a.Y*a.Y; double nX=(X*a.X+Y*a.Y)/d; Y=(-X*a.Y+Y*a.X)/d; X=nX; return *this; }
    inline P& operator *=(const double& c){ X*=c; Y*=c; return *this; }
    inline P& operator /=(const double& c){ X/=c; Y/=c; return *this; }

    inline bool operator ==(const P& a) const { return EQ(X,a.X) and EQ(Y,a.Y); }
    inline bool operator !=(const P& a) const { return !(*this==a); }
    inline bool operator <(const P& a) const { return !EQ(X,a.X)? X<a.X: Y+EPS<a.Y; }
    inline bool operator <=(const P& a) const { return *this<a or *this==a; }
    inline bool operator >(const P& a) const { return !(*this<=a); }
    inline bool operator >=(const P& a) const { return !(*this<a); }
};
P operator *(const double& c, const P& p){ return P(c*p.X, c*p.Y); }
double norm(const P& a){ return a.X*a.X +a.Y*a.Y; }
double abs(const P& a){ return sqrt(a.X*a.X +a.Y*a.Y); }
double arg(const P& a){ return atan2(a.X, a.Y); }
double dot(const P& a, const P& b){ return a.X*b.X +a.Y*b.Y; }
double cross(const P& a, const P& b){ return a.X*b.Y -a.Y*b.X; }
std::ostream& operator <<(std::ostream& lhs, const P& rhs){
    lhs << "(" << rhs.X << ", " << rhs.Y << ")";
    return lhs;
}

using VP = vector<P>;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(dot(b,c-b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) and
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS and dot(s[0]-p, s[1]-p)<EPS;
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int res = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 and b.Y>0 and cross(a,b)<0) res = -res;
    }
    return res;
}

VP convex(VP v){
    VP res;
    int n = v.size();
    sort(v.begin(), v.end());
    for(int i=0; i<n; i++){
        while((int)res.size()>1 and cross(res.back()-res[res.size()-2], v[i]-res.back()) < EPS){
            res.pop_back();
        }
        res.push_back(v[i]);
    }
    int t = res.size();
    for(int i=n-2; i>=0; i--){
        while((int)res.size()>t and cross(res.back()-res[res.size()-2], v[i]-res.back()) < EPS){
            res.pop_back();
        }
        res.push_back(v[i]);
    }
    if((int)res.size() > 1) res.pop_back();
    return res;
}

double perimeter(VP& poly){
    int n = poly.size();
    double res = 0;
    for(int i=0; i<n; i++){
        res += abs(poly[(i+1)%n] -poly[i]);
    }
    return res;
}
bool is_simple(VP &poly){
    int n = poly.size();
    for(int i=0; i<n; i++){
        for(int j=i+2; j<((i==0)? n-1: n); j++){
            if(intersectSS(L(poly[i], poly[(i+1)%n]), L(poly[j], poly[(j+1)%n]))){
                return false;
            }
        }
    }
    return true;
}

vector<int> restore_idxs(VP &a, VP &b){
    vector<int> res;
    for(P p: a){
        for(int i=0; i<(int)b.size(); i++){
            if(p == b[i]){
                res.push_back(i);
                continue;
            }
        }
    }
    return res;
}
VP idx2p(vector<int> &idx, VP &p){
    VP res;
    for(int i: idx){
        res.push_back(p[i]);
    }
    return res;
}
vector<int> rot_unique(vector<int> a){
    int idx = min_element(a.begin(), a.end()) -a.begin();
    a.insert(a.end(), a.begin(), a.begin()+idx);
    a.erase(a.begin(), a.begin()+idx);
    return a;
}

int main(){
    while(1){
        int n,m;
        cin >> n >> m;
        if(n == 0) break;

        VP p(n);
        for(int i=0; i<n; i++){
            cin >> p[i].X >> p[i].Y;
        }
        VP poly = convex(p);
        vector<int> idxs = rot_unique(restore_idxs(poly, p));

        bool ok = false;
        double ans;
        set<vector<int>> used;
        used.insert(idxs);
        priority_queue<pair<double,vector<int>>> wait;
        wait.push({-perimeter(poly), idxs});
        while(!wait.empty()){
            double len = -wait.top().first;
            vector<int> idxs = wait.top().second;
            wait.pop();
            m--;
            if(m == 0){
                ok = true;
                ans = len;
                break;
            }
            for(int i=0; i<(int)idxs.size(); i++){
                for(int j=0; j<n; j++){
                    if(find(idxs.begin(), idxs.end(), j) != idxs.end()) continue;
                    auto nidxs = idxs;
                    nidxs.insert(nidxs.begin()+i, j);
                    nidxs = rot_unique(nidxs);
                    if(used.find(nidxs) != used.end()) continue;
                    VP npoly = idx2p(nidxs, p);
                    if(!is_simple(npoly)) continue;
                    bool ok = true;
                    for(P v: p){
                        if(in_poly(v, npoly) == -1){
                            ok = false;
                            break;
                        }
                    }
                    if(!ok) continue;
                    used.insert(nidxs);
                    wait.push({-perimeter(npoly), nidxs});
                }
            }
        }
        if(ok){
            cout << fixed << setprecision(10);
            cout << ans << endl;
        }else{
            cout << -1 << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3744
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

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

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	/*void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}*/

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};

struct Info{

	bool operator<(const struct Info &arg) const{

		return len_sum > arg.len_sum; //周長の昇順(PQ)
	}

	vector<int> P,REST;
	double len_sum;
};

int N,K;
Point point[25];
map<string,bool> MAP;
string NUM[25];


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}


int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

double calc_len(Vector a){
    return sqrt(a.x*a.x+a.y*a.y);
}

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

Polygon ConvexHull(Polygon V){

	sort(V.begin(),V.end());

	vector<Point> UP,DOWN;

	UP.push_back(V[0]);
	DOWN.push_back(V[0]);

	for(int i = 1; i < V.size(); i++){

		while(UP.size() > 1 && ccw(UP[UP.size()-2],UP[UP.size()-1],V[i]) == COUNTER_CLOCKWISE){

			UP.pop_back();
		}

		while(DOWN.size() > 1 && ccw(DOWN[DOWN.size()-2],DOWN[DOWN.size()-1],V[i]) ==  CLOCKWISE){

			DOWN.pop_back();
		}

		UP.push_back(V[i]);
		DOWN.push_back(V[i]);
	}

	Polygon ret;

	for(int i = 0; i < UP.size(); i++){

		ret.push_back(UP[i]);
	}

	for(int i = DOWN.size()-1; i >= 0; i--){

		ret.push_back(DOWN[i]);
	}

	return ret;
}

double calc_len_sum(Polygon tmp_P){

	int num_P = tmp_P.size();
	double ret = 0;

	for(int i = 0; i < num_P; i++){

		ret += calc_dist(tmp_P[i],tmp_P[(i+1)%num_P]);
	}

	return ret;
}


string makeCode(vector<int> P){

	string ret = NUM[P[0]];

	for(int i = 1; i < P.size(); i++){

		ret = ret + "@" + NUM[P[i]];
	}

	return ret;
}


void func(){

	MAP.clear();

	Polygon first_P;

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&point[i].x,&point[i].y);
		first_P.push_back(point[i]);
	}

	Polygon tmp_P = ConvexHull(first_P);
	double tmp_len_sum = calc_len_sum(tmp_P);

	vector<int> tmp_REST;
	for(int i = 0; i < N; i++){
		bool FLG = false;
		for(int k = 0; k < tmp_P.size(); k++){
			if(point[i] == tmp_P[k]){
				FLG = true;
				break;
			}
		}
		if(!FLG){
			tmp_REST.push_back(i);
		}
	}

	Info first_info;
	for(int i = 0; i < tmp_P.size(); i++){
		if(tmp_P[i] == tmp_P[(i-1+tmp_P.size())%tmp_P.size()])continue;
		for(int k = 0; k < N; k++){
			if(tmp_P[i] == point[k]){
				first_info.P.push_back(k);
				break;
			}
		}
	}

	first_info.REST = tmp_REST;
	first_info.len_sum = tmp_len_sum;

	int CURRENT = 0,NEXT = 1;

	priority_queue<Info> Q[2];
	vector<double> V;

	Q[CURRENT].push(first_info);
	MAP[makeCode(first_info.P)] = true;

	string first_code = makeCode(first_info.P);

	Line tmp_line[2];

	while(true){

		while(!Q[CURRENT].empty()){

			sort(V.begin(),V.end());

			Info info = Q[CURRENT].top();
			Q[CURRENT].pop();

			if(V.size() >= K && info.len_sum > V[K-1])continue;

			V.push_back(info.len_sum);

			int num_P = info.P.size();

			/*★★containsで弾いているので、追加する順番を全探索する。
			 * (追加する順番次第では、残る点がポリゴンの外に出てしまって実現できない線分あり)
			 * 図形が一意かはMAPで調べる★★*/
			for(int i = 0; i < info.REST.size(); i++){
				for(int k = 0; k < num_P; k++){ //付け替える辺のループ

					//k-info.REST[i]-(k+1)%Nとする
					Polygon poly;
					vector<int> work_P;

					for(int a = 0; a <= k; a++){

						poly.push_back(point[info.P[a]]); //座標
						work_P.push_back(info.P[a]); //インデックス
					}

					poly.push_back(point[info.REST[i]]);
					work_P.push_back(info.REST[i]);

					for(int a = k+1; a < num_P; a++){

						poly.push_back(point[info.P[a]]); //座標
						work_P.push_back(info.P[a]); //インデックス
					}

					string tmp_code = makeCode(work_P);
					auto at = MAP.find(tmp_code);

					if(at != MAP.end())continue;

					MAP[tmp_code] = true;

					bool FLG = true;
					//全ての点を含むかチェック
					for(int a = 0; a < info.REST.size(); a++){
						if(a == i)continue;
						if(contains(poly,point[info.REST[a]]) == 0){

							FLG = false;
							break;
						}
					}

					if(!FLG)continue;


					//隣接しない2辺が交差しないかチェック

					tmp_line[0] = Line(point[info.P[k]],point[info.REST[i]]);
					tmp_line[1] = Line(point[info.REST[i]],point[info.P[(k+1)%num_P]]);

					for(int a = 0; a < 2; a++){
						for(int b = 0; b < num_P; b++){
							if(a == 0 && (b == (k-1+num_P)%num_P || b == k))continue;
							if(a == 1 && (b == k || b == (k+1)%num_P))continue;

							Line work_line = Line(point[info.P[b]],point[info.P[(b+1)%num_P]]);

							if(is_Cross(tmp_line[a],work_line)){
								FLG = false;
								break;
							}
						}
						if(!FLG)break;
					}

					if(!FLG)continue;

					Info new_info;
					new_info.P = work_P;
					new_info.len_sum = calc_len_sum(poly);
					for(int a = 0; a < info.REST.size(); a++){
						if(a == i)continue;

						new_info.REST.push_back(info.REST[a]);
					}

					Q[NEXT].push(new_info);
				}
			}
		}

		if(Q[NEXT].size() == 0){

			break;
		}

		swap(CURRENT,NEXT);
	}

	sort(V.begin(),V.end());

	if(V.size() < K){

		printf("-1\n");
		return;
	}

	printf("%.10lf\n",V[K-1]);
}


int main(){

	for(int i = 0; i < 25; i++){

		NUM[i] = to_string(i);
	}

	while(true){

		scanf("%d %d",&N,&K);
		if(N == 0 && K == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 3936
final_rank: 14

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <iomanip>
#include <numeric>

int sign(const int value) {
	if (value == 0) return 0;
	else if (value > 0) return 1;
	else return -1;
}
struct Point {
	int x, y;
};
struct Vector {
	int dx, dy;
	double length() const {
		return std::sqrt(dx * dx + dy * dy);
	}
	int cross(const Vector other) const {
		return dx * other.dy - dy * other.dx;
	}
	int dot(const Vector other) const {
		return dx * other.dx + dy * other.dy;
	}
};
Vector operator-(const Point to, const Point from) {
	return Vector{ to.x - from.x, to.y - from.y };
}
struct Edge {
	Point end_point_a, end_point_b;
	bool is_cross(const Edge other) const {
		return sign((other.end_point_a - end_point_a).cross(end_point_b - end_point_a))* sign((other.end_point_b - end_point_a).cross(end_point_b - end_point_a)) < 0 &&
			sign((end_point_a - other.end_point_a).cross(other.end_point_b - other.end_point_a)) * sign((end_point_b - other.end_point_a).cross(other.end_point_b - other.end_point_a)) < 0;
	}
};

std::vector<std::vector<int>> next_state(const std::vector<int>& polygon, const std::vector<Point>& points) {
	std::vector<int> not_used; not_used.reserve(points.size() - polygon.size());
	for (auto i = 0; i < points.size(); ++i) {
		if (std::find(polygon.begin(), polygon.end(), i) == polygon.end()) {
			not_used.push_back(i);
		}
	}
	std::vector<std::vector<int>> result;
	for (auto i = 0; i < polygon.size(); ++i) {
		const auto from = points[polygon[i]];
		const auto to = points[polygon[(i + 1) % polygon.size()]];
		const auto ft = from - to;
		for (const auto other : not_used) {
			const auto of = Edge{ points[other], from };
			const auto ot = Edge{ points[other], to };
			bool can_make = true;
			for (auto j = 1; j < polygon.size(); ++j) {
				const auto edge = Edge{ points[polygon[(i + j) % polygon.size()]], points[polygon[(i + j + 1) % polygon.size()]] };
				if (edge.is_cross(of) || edge.is_cross(ot)) {
					can_make = false;
					break;
				}
			}
			if (!can_make) continue;
			const auto vf = from - points[other];
			const auto vt = to - points[other];
			for (auto a = 0; a < not_used.size(); ++a) {
				if (not_used[a] == other) continue;
				const auto p = points[not_used[a]];
				const auto vec = p - points[other];
				if (sign(vec.cross(vf)) * sign(vec.cross(vt)) < 0 && sign(ft.cross(p - to)) * sign((points[other] - to).cross(p - to)) < 0) {
					can_make = false;
					break;
				}
			}
			if (!can_make) continue;
			result.push_back(polygon); result.back().reserve(polygon.size() + 1);
			result.back().insert(std::next(result.back().begin(), i + 1), other);
		}
	}
	return result;
}
std::vector<int> convex_hull(const std::vector<Point>& points) {
	std::vector<int> indices(points.size());
	std::iota(indices.begin(), indices.end(), 0);
	std::sort(indices.begin(), indices.end(), [&points](const int i, const int j) {return points[i].x == points[j].x ? points[i].y > points[j].y : points[i].x < points[j].x; });
	std::vector<int> result{ indices[0], indices[1] };
	for (auto i = 2; i < indices.size(); ++i) {
		while (result.size() >= 2 && (points[result[result.size() - 1]] - points[result[result.size() - 2]]).cross(points[indices[i]] - points[result[result.size() - 1]]) > 0) {
			result.pop_back();
		}
		result.push_back(indices[i]);
	}
	for (int i = indices.size() - 2; i >= 0; --i) {
		while (result.size() >= 2 && (points[result[result.size() - 1]] - points[result[result.size() - 2]]).cross(points[indices[i]] - points[result[result.size() - 1]]) > 0) {
			result.pop_back();
		}
		result.push_back(indices[i]);
	}
	result.pop_back();
	return result;
}
double cal_k_th_hull(const std::vector<Point> points, const int k) {
	const auto perimeter = [points](const std::vector<int>& polygon) {
		double result{ 0 };
		for (auto i = 0; i < polygon.size(); ++i) {
			result += (points[polygon[(i + 1) % polygon.size()]] - points[polygon[i]]).length();
		}
		return result;
	};
	std::vector<std::vector<int>> suspects{ convex_hull(points) };
	double last_perimeter = 0;
	for (auto i = 0; i < k; ++i) {
		if (suspects.empty()) return -1;
		const auto min = std::min_element(suspects.begin(), suspects.end(), [&perimeter](const std::vector<int>& a, const std::vector<int>& b) {return perimeter(a) < perimeter(b); });
		last_perimeter = perimeter(*min);
		//std::cout << std::setprecision(15) << std::fixed << last_perimeter << '\n';
		const auto next = next_state(*min, points);
		suspects.erase(min);
		for (const auto &n : next) {
			if (std::any_of(suspects.begin(), suspects.end(), [&n](const std::vector<int>& s) {
				if (s.size() != n.size()) return false;
				for (auto i = 0; i < s.size(); ++i) if (s[i] != n[i]) return false;
				return true;
				})) continue;
			suspects.push_back(n);
		}
	}
	return last_perimeter;
}

int main() {
	while (true) {
		int n, k; std::cin >> n >> k;
		if (n == 0 && k == 0) break;
		std::vector<Point> points(n);
		for (auto& p : points) std::cin >> p.x >> p.y;
		const auto perimeter = cal_k_th_hull(points, k);
		if (perimeter >= 0) {
			std::cout << std::setprecision(15) << std::fixed << perimeter << '\n';
		}
		else {
			std::cout << "-1\n";
		}
	}
}
accuracy: 1
time_ms: 20
memory_kb: 3376
final_rank: 1

code_snippet: #include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cmath>
#include <complex>
#include <set>
#include <map>
using namespace std;

#define ALL(v) (v).begin(),(v).end()

typedef double D;
typedef complex<D> P;
typedef const P &rP;

const D EPS = 1e-9;

namespace std{
	bool operator< (const P &p, const P &q){
		if(p.real() != q.real()){ return p.real() < q.real(); }
		return p.imag() < q.imag();
	}
}

void normalize(vector<int> &v){
	rotate(v.begin(), min_element(ALL(v)), v.end());
}

D dot(rP va, rP vb){
	return real(va) * real(vb) + imag(va) * imag(vb);
}

D cross(rP va, rP vb){
	return real(va) * imag(vb) - imag(va) * real(vb);
}

int ccw(P a, P b, P c) {
	b -= a;
	c -= a;
	if (cross(b, c) > 0)	 return +1;			 // counter clockwise
	if (cross(b, c) < 0)	 return -1;			 // clockwise
	if (dot(b, c) < 0)		 return +2;			 // c--a--b on line
	if (norm(b) < norm(c)) return -2;			 // a--b--c on line
	return 0;
}

bool intersectSS(P pa1, P pa2, P pb1, P pb2){
	P da12 = pa2 - pa1;
	P db21 = pb1 - pb2;
	P dab1 = pb1 - pa1;

	D d = cross(da12, db21);

	if(abs(d) > EPS){
		D t = cross(dab1, db21) / d;
		D s = cross(da12, dab1) / d;
		
		if( (-EPS < t && t < 1.0 + EPS) && (-EPS < s && s < 1.0 + EPS) ){
			return true;
		}
	}
	return false;
}

bool containstript(rP a, rP b, rP c, rP pt){
	int x = ccw(a, b, pt);
	int y = ccw(b, c, pt);
	int z = ccw(c, a, pt);
	if(x == 1 && y == 1 && z == 1){ return true; }
	if(x == -1 && y == -1 && z == -1){ return true; }
	return false;
}

vector<P> convex_hull(vector<P> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());

	vector<P> ch(2*n);
	for (int i = 0; i < n; ch[k++] = ps[i++]){ // lower-hull
		while (k >= 2 && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
	}
	for (int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--]){ // upper-hull
		while (k >= t && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
	}
	ch.resize(k-1);
	return ch;
}

struct solver{
	struct polygon{
		D len;
		vector<int> idxs;

		polygon(D l, const vector<int> &i) : len(l), idxs(i) {}

		bool operator< (const polygon &p) const{
			return len < p.len;
		}
	};

	rP getpt(const vector<int> &v, size_t i){
		return points[i == v.size() ? v[0] : v[i]];
	}

	size_t k;
	vector<P> points;
	map<P,int> toidx;
	vector<polygon> pols;
	set<vector<int>> seen;
	
	polygon makeplg(vector<int> idxs){
		normalize(idxs);
		int sz = idxs.size();
		D len = 0;
		for(int i = 0; i < sz; ++i){
			len += abs(getpt(idxs, i) - getpt(idxs, i + 1));
		}
		return polygon(len, idxs);
	}

	void add(const vector<int> &w){
		set<int> st;
		for(int x : w){
			if(!st.insert(x).second){ return; }
		}
		polygon pl = makeplg(w);
		if(seen.insert(pl.idxs).second){
			pols.insert(upper_bound(ALL(pols), pl), pl);
			while(pols.size() > k){ pols.pop_back(); }
		}
	}
	
	void validateadd(const vector<int> &v, int pos, int pi){
		int sz = v.size();
		for(int i = 0; i < sz; ++i){
			if(i + 1 == pos){ continue; }
			if(!(pos == 1 && i == sz - 1) && i + 2 != pos){
				if(intersectSS(getpt(v, i), getpt(v, i + 1), getpt(v, pos - 1), points[pi])){
					return;
				}
			}
			if(pos != i && !(pos == sz && i == 0)){
				if(intersectSS(getpt(v, i), getpt(v, i + 1), points[pi], getpt(v, pos))){
					return;
				}
			}
		}
		for(rP c : points){
			if(containstript(getpt(v, pos - 1), points[pi], getpt(v, pos), c)){
				return;
			}
		}
		vector<int> w = v;
		w.insert(w.begin() + pos, pi);
		add(w);
	}

	D solve(int n, int k_){
		k = k_;
		for(int i = 0; i < n; ++i){
			D x, y;
			cin >> x >> y;
			P p(x, y);
			points.push_back(p);
			toidx[p] = i;
		}

		vector<P> conv0 = convex_hull(points);
		vector<int> v0;
		for(rP p : conv0){
			v0.push_back(toidx[p]);
		}
		add(v0);

		for(size_t i = 0; i < pols.size(); ++i){
			polygon cur = pols[i];
			int sz = cur.idxs.size();
			for(int pos = 1; pos <= sz; ++pos)
			for(int pi = 0; pi < n; ++pi){
				validateadd(cur.idxs, pos, pi);
			}
		}

		if(pols.size() >= k){
			return pols[k - 1].len;
		}
		return -1;
	}
};

int main(){
	cout << fixed << setprecision(9);

	int n, k;
	while(cin >> n >> k && n){
		D ans = solver().solve(n, k);
		cout << ans << endl;
	}
}
accuracy: 1
time_ms: 20
memory_kb: 3476
final_rank: 3

code_snippet: // tabun O(KN^4)

   #include <bits/stdc++.h>
using namespace std;
 #define int long long
 #define ll long long
  #define  mp make_pair
  #define  pb push_back
  #define EPS (1e-10)


class Point{
	public:
	double x,y;
	Point(double x=0,double y=0):x(x),y(y) {}
	Point operator + (Point p) {return Point(x+p.x,y+p.y);}
	Point operator - (Point p) {return Point(x-p.x,y-p.y);}
	Point operator * (double a) {return Point(x*a,y*a);}
	Point operator / (double a) {return Point(x/a,y/a);}
	double absv() {return sqrt(norm());}
	double norm() {return x*x+y*y;}
	bool operator < (const Point &p) const{
		return x != p.x ? x<p.x: y<p.y;
 	}
	bool operator == (const Point &p) const{
		return fabs(x-p.x)<EPS && fabs(y-p.y)<EPS;
	}
};

double d(Point p,Point q){
	return sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y));
}

vector<int> convexhall(vector<Point>  ve){
	sort(ve.begin(),ve.end());
	
	vector<int> ue;
	ue.pb(0);
	int n=ve.size();
	
	for(int i=1;i<n;i++){
		while(1){
			int t=ue.size();
			
			if(t==1){
				ue.pb(i);
				break;
			}
			
			if((ve[ue[t-1]].y-ve[ue[t-2]].y)*(ve[i].x-ve[ue[t-2]].x)<(ve[ue[t-1]].x-ve[ue[t-2]].x)*(ve[i].y-ve[ue[t-2]].y)){
				ue.pop_back();
				continue;
			}
			else{
				ue.pb(i);
				break;
			}
			
		}
	}
	vector<int> si;
	si.pb(0);
	
	for(int i=1;i<n;i++){
		while(1){
			int t=si.size();
			
			if(t==1){
				si.pb(i);
				break;
			}
			
			if((ve[si[t-1]].y-ve[si[t-2]].y)*(ve[i].x-ve[si[t-2]].x)>(ve[si[t-1]].x-ve[si[t-2]].x)*(ve[i].y-ve[si[t-2]].y)){
				si.pop_back();
				continue;
			}
			else{
				si.pb(i);
				break;
			}
			
		}
	}
	
	assert(ue[0]==0);
	assert(si[0]==0);
	assert(ue.back()==n-1);
	assert(si.back()==n-1);
	si.pop_back();
	while(si.size()){
		ue.pb(si.back());
		si.pop_back();
	}
	ue.pop_back();
	return ue;
	
}

double cr(Point x,Point y){
	return x.x*y.y-x.y*y.x;
}

bool kousa(Point xs,Point xt,Point ys,Point yt){
	
	double v1=cr(xt-xs,ys-xs)*cr(yt-xs,xt-xs);
	double v2=cr(yt-ys,xs-ys)*cr(xt-ys,yt-ys);
	
	return (v1>0 && v2>0) ;
}

vector<Point> points;

double nagasa(vector<int> ve){
	int n=ve.size();
	double ans=d(points[ve[0]],points[ve[n-1]]);
	for(int i=0;i<n-1;i++)ans+=d(points[ve[i]],points[ve[i+1]]);
	return ans;
}


bool ok(vector<int> ve,int zen){
	int n=ve.size();
	
	for(int i=0;i<n;i++)for(int j=i+2;j<n;j++){
		//[i,i+1] [j,j+1]
		if(i==0 && j==n-1) continue;
		
		if(kousa(points[ve[i]],points[ve[i+1]],points[ve[j]],points[ve[(j+1)%n]]))return 0;
	}
	
	bool used[30]={};
	for(auto v:ve)used[v]=1;
	for(int v=0;v<zen;v++)if(!used[v]){
		Point X=points[v];
		int cnt=0;
		for(int i=0;i<n;i++){
			Point p=points[ve[i]];
			Point q=points[ve[(i+1)%n]];
			
			if(p.y>q.y)swap(p,q);
			if(p.y>X.y || X.y>q.y)continue;
			if(cr(X-p,q-p)>0)cnt++;
			
		}
		if(cnt%2==0) return 0;
		
	}
	
	
	return 1;
}

double solve(){
	int n,k;
	cin>>n>>k;
	if(n==0) exit(0);
	points.clear();
	for(int i=0;i<n;i++){
		double x,y;
		cin>>x>>y;
		Point p;
		p.x=x*cos(1)+y*sin(1);
		p.y=-x*sin(1)+y*cos(1);
		
		points.pb(p);
	}
	sort(points.begin(),points.end());
	vector<int> CH =convexhall(points);
	
	priority_queue<pair<double,vector<int>>,vector<pair<double,vector<int>>>,greater<pair<double,vector<int>>>> pq;   
	
	pq.push(mp(nagasa(CH),CH));
	set<vector<int>> se;
	int cnt=0;
	while(pq.size()){
		auto Z=pq.top();
		pq.pop();
		
		if(se.count(Z.second))continue;
		
		cnt++;
		
		if(cnt==k){
			return Z.first;
		}
		se.insert(Z.second);
		bool use[30]={};
		for(auto v:Z.second)use[v]=1;
		for(int v=0;v<n;v++)if(!use[v]){
			// vを追加
			int m=Z.second.size();
			for(int i=0;i<m;i++){
				vector<int> NEW;
				for(int j=0;j<m;j++){
					NEW.pb(Z.second[j]);
					if(j==i)NEW.pb(v);
				}
				
				if(ok(NEW,n)){
					
					pq.push(mp(nagasa(NEW),NEW));
				}
				
			}
			
		}
		
	}
	return -1;
}


 signed main(){
 	
 
    	//       cin.tie(0);
   		//	ios::sync_with_stdio(false);
 	while(1){
 		double ans=solve();
 		if(ans<0)printf("-1\n");
 		else printf("%.14lf\n",ans);
 	}
 	
 	return 0;
 
  }
accuracy: 1
time_ms: 40
memory_kb: 3400
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
#define F first
#define S second

template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}



namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    
    static bool comp(const P &p1,const P &p2){
        if(p1.real()==p2.real()){return p1.imag()<p2.imag();}
        return p1.real()<p2.real();
    }
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    bool intersectSL(P p1,P p2,P vec){
        vec/=abs(vec); p1/=vec; p2/=vec;
        return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);
    }
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){
        if(dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS){return false;}
        if(dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS){return false;}
        return intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);
    }
    
    P crosspointLL(P p1,P p2,P vec){
        if(abs(cross(p2-p1,vec))<EPS){return vec;}
        return vec*cross(p2-p1,p2)/cross(p2-p1,vec);
    }
    
    P crosspointLL(P p1,P p2,P p3,P p4){
        return p4+crosspointLL(p1-p4,p2-p4,p3-p4);
    }
    
    bool intersectShL(P p1,P p2,P vec){
        vec/=abs(vec);
        return intersectSL(p1,p2,vec) &&
        crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;
    }
    
    bool intersectShL(P p1,P p2,P p3,P p4){
        return intersectShL(p1-p3,p2-p3,p4-p3);
    }
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){
        if(dot(p2-p1,x-p1)<-EPS){return abs(x-p1);}
        if(dot(p1-p2,x-p2)<-EPS){return abs(x-p2);}
        return distLP(p1,p2,x);
    }
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        int s=A.size();
        vector<bool> cnt(s,false);
        for(int i=0;i<(int)poly.size();i++){
            int k=(i+1)%poly.size();
            if(distSP(poly[i],poly[k],p)<EPS){return 0;}
            for(int j=0;j<s;j++){
                if(intersectShL(poly[i],poly[k],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<s;j++){if(cnt[j]){in++;}}
        return in>s/2?1:-1;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        auto fnc=[&](){
            for(auto &I:pts){
                if(!ret.empty() && I==ret.back()){continue;}
                while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){
                    ret.pop_back();
                }
                ret.push_back(I);
            }
        };
        fnc();
        reverse(pts.begin(),pts.end());
        fnc();
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
};

using namespace Geometry;



D cul(const vector<int> &poly,const vector<P> &A){
    D ret=0;
    int N=(int)poly.size();
    for(int i=1;i<=N;i++){ret+=abs(A[poly[i-1]]-A[poly[i%N]]);}
    return ret;
}


bool OK(const vector<int> &poly,const vector<P> &A){
    int N=A.size(),M=poly.size();
    vector<P> B(M);
    for(int i=0;i<M;i++){B[i]=A[poly[i]];}
    for(int i=1;i<=M;i++){
        for(int j=i+2;j<=M;j++){
            if(i==1 && j==M){continue;}
            if(intersectSS(B[i-1],B[i%M],B[j-1],B[j%M])){return false;}
        }
    }
    for(int i=0;i<N;i++){if(contain(B,A[i])==-1){return false;}}
    return true;
}


bool solve(){
    int n,k;
    cin>>n>>k;
    if(n==0){return false;}
    vector<P> A(n);
    cin>>A;
    typedef vector<int> poly;
    set<poly> used;
    priority_queue<pair<D,poly>,vector<pair<D,poly>>,greater<pair<D,poly>>> Q;
    vector<pair<D,poly>> ans;
    auto cvx=convexhull(A);
    vector<int> pl(cvx.size(),-1);
    for(int i=0;i<cvx.size();i++){
        for(int j=0;j<n;j++){
            if(cvx[i]==A[j]){pl[i]=j;}
        }
    }
    //cout<<pl<<endl;
    //cout<<OK(pl,A)<<endl;
    Q.push({cul(pl,A),pl});
    used.insert(Q.top().S);
    while(!Q.empty() && ans.size()<k){
        ans.push_back(Q.top()); Q.pop();
        pl=ans.back().S;
        set<int> in_poly;
        for(auto &I:pl){in_poly.insert(I);}
        for(int i=0;i<n;i++){
            if(!in_poly.count(i)){
                for(int j=1;j<=pl.size();j++){
                    vector<int> N(pl.size()+1);
                    for(int k=0;k<=pl.size();k++){
                        if(k<j){N[k]=pl[k];}
                        else if(k==j){N[k]=i;}
                        else{N[k]=pl[k-1];}
                    }
                    if(!used.count(N) && OK(N,A)){Q.push({cul(N,A),N}); used.insert(N);}
                }
            }
        }
    }
    if(ans.size()<k){cout<<-1<<endl;}
    else{cout<<fixed<<setprecision(12)<<ans.back().F<<endl;}
    //for(auto &I:ans){cout<<I<<endl;}
    
    return true;
}


int main(){
    while(solve());
    
    return 0;
}
accuracy: 1
time_ms: 2160
memory_kb: 3584
final_rank: 19