#include "triangles.h"
#include <bits/stdc++.h>

using namespace std;

#ifdef lisie_bimbi

namespace {
    constexpr int kMaxQ = 2'000'000;
    int verbose = 0;

    void WA(const string& msg) {
        cout << "WA " << msg << "\n";
        exit(0);
    }

    int n, group;
    vector<pair<int64_t, int64_t>> points;
    uint64_t cur_queries;

    void ValidateTriangle(const Triangle& t) {
        if (t.i < 0 || t.i >= n) {
            WA("triangle i is out of range [0,n-1]");
        }
        if (t.j < 0 || t.j >= n) {
            WA("triangle j is out of range [0,n-1]");
        }
        if (t.k < 0 || t.k >= n) {
            WA("triangle k is out of range [0,n-1]");
        }
        if (t.i == t.j) {
            WA("triangle i and j are equal");
        }
        if (t.i == t.k) {
            WA("triangle i and k are equal");
        }
        if (t.j == t.k) {
            WA("triangle j and k are equal");
        }
    }

    uint64_t GetDoubleArea(const Triangle& t) {
        pair<int64_t, int64_t> v1 = {points[t.j].first - points[t.i].first, points[t.j].second - points[t.i].second};
        pair<int64_t, int64_t> v2 = {points[t.k].first - points[t.i].first, points[t.k].second - points[t.i].second};
        return abs(v1.first * v2.second - v1.second * v2.first);
    }

    void LogCompare(const vector<Triangle>& left, const vector<Triangle>& right) {
        cout << "compare #" << cur_queries << ":\n";
        cout << "left " << left.size() << " triangle" << (left.size() > 1 ? "s" : "") << ": ";
        for (size_t i = 0; i < left.size(); ++i) {
            cout << (i == 0 ? "(" : ", (") << left[i].i << "," << left[i].j << "," << left[i].k << ")";
        }
        cout << "\n";
        cout << "right " << right.size() << " triangle" << (right.size() > 1 ? "s" : "") << ": ";
        for (size_t i = 0; i < left.size(); ++i) {
            cout << (i == 0 ? "(" : ", (") << right[i].i << "," << right[i].j << "," << right[i].k << ")";
        }
        cout << "\n";
    }
}

int compare(const vector<Triangle>& left, const vector<Triangle>& right) {
    cur_queries++;
    if (cur_queries > kMaxQ) {
        WA("too many queries");
    }
    if (verbose > 0) {
        LogCompare(left, right);
    }
    if (left.empty()) {
        WA("left should be non-empty");
    }
    if (right.empty()) {
        WA("right should be non-empty");
    }
    if (left.size() + right.size() > 4) {
        WA("the number of triangles should be at most 4");
    }
    for (const auto& t : left) {
        ValidateTriangle(t);
    }
    for (const auto& t : right) {
        ValidateTriangle(t);
    }

    uint64_t left_area = 0;
    for (const auto& t : left) {
        left_area += GetDoubleArea(t);
    }
    uint64_t right_area = 0;
    for (const auto& t : right) {
        right_area += GetDoubleArea(t);
    }

    if (verbose > 0) {
        cout << "result: ";
        if (left_area < right_area) {
            cout << "left is smaller (-1)\n";
        } else if (left_area == right_area) {
            cout << "equal (0)\n";
        } else {
            cout << "right is smaller (1)\n";
        }
    }

    return left_area < right_area ? -1 : (left_area > right_area ? 1 : 0);
}
#endif

using tr = Triangle;

bool in(int a, int b, int c, int d){
    if(compare({tr(a, b, c)}, {tr(a, b, d), tr(a, c, d), tr(b, c, d)}) == 0){
        return 1;
    }else{
        return 0;
    }
}

std::vector<std::vector<int>> solve4(int n) {
    if(compare({tr(0, 1, 2)}, {tr(3, 0, 1), tr(3, 0, 2), tr(3, 1, 2)}) == 0){
        return {{0, 1, 3}, {0, 2, 3}, {1, 2, 3}};
    }
    for(int i = 0; i < 4; i++){
        vector<int> v;
        for(int j = 0; j < n; j++){
            if(j != i){
                v.push_back(j);
            }
        }
        v.push_back(i);
        if(in(v[0], v[1], v[2], v[3])){
            return {{v[0], v[1], v[3]}, {v[0], v[2], v[3]}, {v[1], v[2], v[3]}};
        }
    }
    if(compare({tr(0, 1, 2), tr(0, 1, 3)}, {tr(0, 2, 3), tr(1, 2, 3)}) == 0){
        return {{0, 1, 2}, {0, 1, 3}};
    }
    if(compare({tr(0, 1, 2), tr(0, 2, 3)}, {tr(0, 1, 3), tr(1, 2, 3)}) == 0){
        return {{0, 1, 2}, {0, 2, 3}};
    }
    if(compare({tr(0, 1, 2), tr(1, 2, 3)}, {tr(0, 2, 3), tr(0, 1, 3)}) == 0){
        return {{0, 1, 2}, {1, 2, 3}};
    }
    return {};
}

vector<vector<int>> ans;

void calc(int a, int b, int c, vector<int> z){
    if(z.empty()){
        ans.push_back({a, b, c});
        return;
    }
    int c1 = z[0];
    for(auto i : z){
        if(compare({tr(a, b, c1)}, {tr(a, b, i)}) == 1){
            c1 = i;
        }
    }
    vector<int> z1, z2;
    for(auto i : z){
        if(in(a, c, c1, i)){
            z1.push_back(i);
        }else{
            z2.push_back(i);
        }
    }
    ans.push_back({a, b, c1});
    calc(a, c, c1, z1);
    calc(b, c, c1, z2);
}

std::vector<std::vector<int>> solve(int n) {
    ans.clear();
    if(n == 4){
        return solve4(n);
    }
    vector<int> now = {0, 1, 2};
    for(int i = 0; i < n; i++){
        if((i == now[0]) || (i == now[1]) || (i == now[2])){
            continue;
        }
        if(compare({tr(now[0], now[1], now[2])}, {tr(now[0], now[1], i)}) == -1){
            now[2] = i;
        }
    }
    for(int i = 0; i < n; i++){
        if((i == now[0]) || (i == now[1]) || (i == now[2])){
            continue;
        }
        if(compare({tr(now[0], now[1], now[2])}, {tr(i, now[1], now[2])}) == -1){
            now[0] = i;
        }
    }
    for(int i = 0; i < n; i++){
        if((i == now[0]) || (i == now[1]) || (i == now[2])){
            continue;
        }
        if(compare({tr(now[0], now[1], now[2])}, {tr(now[0], i, now[2])}) == -1){
            now[1] = i;
        }
    }
    vector<int> z;
    for(int i = 0; i < n; i++){
        if((i != now[0]) && (i != now[1]) && (i != now[2])){
            z.push_back(i);
        }
    }
    calc(now[0], now[1], now[2], z);
    return ans;
}

#ifdef lisie_bimbi

int main() {
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout); 

    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n;
    points.resize(n);
    for (int i = 0; i < n; ++i) {
        cin >> points[i].first >> points[i].second;
    }
    cur_queries = 0;

    auto result = solve(n);
    cout << result.size() << "\n";
    for (const auto& polygon : result) {
        cout << polygon.size() << "\n";
        for (size_t i = 0; i < polygon.size(); ++i) {
            cout << polygon[i] << " \n"[i + 1 == polygon.size()];
        }
    }
    if (verbose > 0) {
        cout << cur_queries << (cur_queries == 1 ? " query\n" : " queries\n");
    }

    return 0;
}
#endif