Problem: cf1340_e
Difficulty: hard
Categories: graph, greedy
Time limit: 1000 ms, memory limit: 256 MB

Unfortunately, a mistake was found in the proof of the author's solution to this problem. Currently, we don't know the absolutely correct solution. However, you can solve this task, but if your solution passes all the tests, it is not guaranteed to be correct. If your solution has passed all the tests and you are sure that it is correct, you can write to one of the contest authors about it.

Surely you all read the book "Alice in Wonderland". In this task, Nastya got to the country of Three strange Bees. The bees are strange because their honeycombs are pentagonal. Nastya got there illegally, so she wants bees not to catch her. Help the bees punish the intruder!

This is an interactive problem.

A beehive is a connected undirected graph where bees and Nastya can move along the edges. A graph satisfies two properties:

* The degree of any of its vertex is no more than $3$.
* For each edge, there exists a cycle of length not greater than $5$ passing through this edge.

There are three bees and Nastya. You play for bees. Firstly, you choose the vertices where you put the bees. Then Nastya chooses another vertex in which she will initially appear. One move is first moving the bees, then Nastya, in turn:

1. For each of your bees, you can either move each one along some edge from the vertex they are currently staying or leave it in place.
2. Then Nastya will necessarily move along some edge of the graph from the vertex she is currently staying/.

You win if at least one of the bees and Nastya are in the same vertex at any time of the game.

If this situation does not occur after $n$ moves, then you lose.

Several bees can be in the same vertex.

Input

The first line contains two integers $n$ $(4 \leq n \leq 5000)$ and $m$ $(n \leq m \leq 3n)$  — the number of vertices and edges in the graph.

Each of the next $m$ lines contains two integers $v$ and $u$ $(1 \leq v, u \leq n)$, which mean that there is an edge between the vertices $v$ and $u$. It is guaranteed that the graph is connected, does not contain loops that the degree of any vertex does not exceed $3$ and a cycle of length no more than $5$ passes through each edge. Note that the graph may contain multiple edges.

Interaction

At each turn, you must output exactly three vertices $a, b, c$ $(1 \leq a, b, c \leq n)$. For the first time, $3$ vertices displayed will indicate which vertices you originally placed bees on. In response, you will receive the vertex where the jury placed Nastya. Each next $3$ vertices will indicate where the $3$ bees move at your turn. Each of the bees can, regardless of other bees, both remain at the current vertex and move along the edge. After the next output of $3$ vertices, in response, you get the number of the new vertex to which Nastya went.

As soon as one of the bees is at the same vertex with Nastya or you have reached the limit on the number of moves, your program should stop working. That is if you made a move, and one of the bees ended up at the same vertex with Nastya, your program must stop working, or if Nastya made a move and ended up at the same vertex with one of the bees, you should not make your move and the program should stop working.

If the number of moves exceeds limit ($n$, where $n$ is the number of vertices), you will get the Wrong Answer verdict.

Your solution may receive the verdict Idleness Limit Exceeded if you don't output anything or forget to flush the output buffer.

To flush the output buffer, you need to do the following immediately after printing the query and the line end:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* for other languages see documentation.

In this problem interactor is adaptive. This means that depending on all your previous moves, Nastya's behavior may change.

Examples

Input

```
5 5
1 2
2 3
3 4
4 5
5 1
4
5
```

Output

```
1 1 2
1 5 3
```

Input

```
8 9
1 2
2 3
3 4
4 5
5 1
5 6
6 7
7 8
8 4
1
5
```

Output

```
7 3 3
6 2 2
5 3 1
```

Note

Let Nastya be a green chip, and three numbered red ones are three bees.

In the first test, the movement of the heroes looks like this.

 ![](https://espresso.codeforces.com/681226301bceb8882bbd73c62195ea5e0cd934f4.png) After selecting the starting vertices.  ![](https://espresso.codeforces.com/e74b5dfad9cb0b1679c38e835016a5d04762021a.png) The first move after the bees move.  ![](https://espresso.codeforces.com/fc9f6c44b3c02e114d39af25d4f8f22e208d5fad.png) The first move after the Nastya's move. The first bee caught Nastya. 

In the second test, the movement of the heroes looks like this.

 ![](https://espresso.codeforces.com/0945063f5bde2c495484066cb15e6ffc4b59af1f.png) After selecting the starting vertices.  ![](https://espresso.codeforces.com/ee8ff1f13c25ad4d025d01d85ea7ce55a941de51.png) The first move after the bees move.  ![](https://espresso.codeforces.com/d543d752047d335962f95d72004206da230cfe16.png) The first move after the Nastya's move.  ![](https://espresso.codeforces.com/82ba746a8735c7d033253a8808217df3430971cf.png) The second move after the bees move. The first bee caught Nastya.

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
#include <csignal>
using namespace std;

static long long queries = 0;      
static long long query_limit = 0;  
static long long hard_cap = 0;

static void log_metrics() {
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

static bool parseLL(const string& s, long long& out) {
    if (s.empty()) return false;
    int i = 0;
    int sign = 1;
    if (s[i] == '+' || s[i] == '-') {
        if (s[i] == '-') sign = -1;
        i++;
    }
    if (i >= (int)s.size()) return false;
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        unsigned char c = (unsigned char)s[i];
        if (c < '0' || c > '9') return false;
        int d = c - '0';
        if (val > (LLONG_MAX - d) / 10) return false;
        val = val * 10 + d;
    }
    out = sign * val;
    return true;
}

static bool readThreeVertices(int& a, int& b, int& c) {
    string sa, sb, sc;
    if (!(cin >> sa)) return false;
    if (!(cin >> sb)) return false;
    if (!(cin >> sc)) return false;
    long long la, lb, lc;
    if (!parseLL(sa, la) || !parseLL(sb, lb) || !parseLL(sc, lc)) return false;
    if (la < INT_MIN || la > INT_MAX || lb < INT_MIN || lb > INT_MAX || lc < INT_MIN || lc > INT_MAX) return false;
    a = (int)la;
    b = (int)lb;
    c = (int)lc;
    return true;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);
    signal(SIGPIPE, SIG_IGN);

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

    int n = inf.readInt(4, 5000, "n");
    int m = inf.readInt(n, 3 * n, "m");

    vector<pair<int,int>> edges;
    edges.reserve(m);
    vector<vector<int>> g(n + 1);
    for (int i = 0; i < m; i++) {
        int u = inf.readInt(1, n, "u");
        int v = inf.readInt(1, n, "v");
        edges.push_back({u, v});
        g[u].push_back(v);
        g[v].push_back(u);
    }

    
    vector<int> script;
    script.reserve(n + 2);
    while (true) {
        inf.skipBlanks();
        if (inf.eof()) break;
        int x = inf.readInt(1, n, "script_pos");
        script.push_back(x);
    }

    query_limit = n;
    hard_cap = max(200000LL, 10LL * query_limit);

    
    log_metrics();

    
    cout << n << " " << m << "\n";
    for (auto &e : edges) cout << e.first << " " << e.second << "\n";
    cout.flush();

    auto isAdjOrSame = [&](int from, int to) -> bool {
        if (from == to) return true;
        for (int nei : g[from]) if (nei == to) return true;
        return false;
    };
    auto isAdjStrict = [&](int from, int to) -> bool {
        if (from == to) return false;
        for (int nei : g[from]) if (nei == to) return true;
        return false;
    };
    auto deterministicNext = [&](int cur) -> int {
        int best = -1;
        for (int nei : g[cur]) {
            if (best == -1 || nei < best) best = nei;
        }
        if (best == -1) finish(_pe, "graph has isolated vertex (unexpected)");
        if (best == cur) finish(_pe, "deterministicNext produced non-move (unexpected)");
        return best;
    };
    auto scriptedOrDet = [&](int idx, int cur) -> int {
        if (idx >= 0 && idx < (int)script.size()) {
            int nxt = script[idx];
            if (1 <= nxt && nxt <= n && isAdjStrict(cur, nxt)) return nxt;
        }
        return deterministicNext(cur);
    };

    
    int b1, b2, b3;
    if (!readThreeVertices(b1, b2, b3)) finish(_pe, "failed to read initial bee positions (expected 3 integers)");
    if (b1 < 1 || b1 > n || b2 < 1 || b2 > n || b3 < 1 || b3 > n) finish(_wa, "initial bee position out of range");

    array<int,3> bees = {b1, b2, b3};

    
    int nastya = (script.empty() ? 1 : script[0]);
    if (nastya < 1 || nastya > n) nastya = 1;

    cout << nastya << "\n";
    cout.flush();

    
    if (bees[0] == nastya || bees[1] == nastya || bees[2] == nastya) {
        finish(_ok, "caught at initial placement");
    }

    
    for (int move = 1; move <= n; move++) {
        int n1, n2, n3;
        if (!readThreeVertices(n1, n2, n3)) finish(_pe, "failed to read bee move (expected 3 integers)");

        queries++;
        if (queries > hard_cap) finish(_pe, "hard cap exceeded (too many moves/outputs)");

        if (n1 < 1 || n1 > n || n2 < 1 || n2 > n || n3 < 1 || n3 > n) finish(_wa, "bee move out of range");
        if (!isAdjOrSame(bees[0], n1) || !isAdjOrSame(bees[1], n2) || !isAdjOrSame(bees[2], n3)) {
            finish(_wa, "illegal bee move (must stay or move along an edge)");
        }

        bees = {n1, n2, n3};

        
        if (bees[0] == nastya || bees[1] == nastya || bees[2] == nastya) {
            finish(_ok, "caught after bees move");
        }

        
        int nextNastya = scriptedOrDet((int)queries, nastya);
        nastya = nextNastya;

        cout << nastya << "\n";
        cout.flush();

        
        if (bees[0] == nastya || bees[1] == nastya || bees[2] == nastya) {
            finish(_ok, "caught after Nastya move");
        }

        
        if (move == n) {
            finish(_wa, "Nastya escaped after n moves");
        }
    }

    finish(_wa, "unexpected termination");
}


Adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

static long long queries = 0;
static long long query_limit = 0;

static void log_metrics() {
    try {
        tout << "queries=" << queries << '\n';
        tout << "query_limit=" << query_limit << '\n';
        tout.flush();
    } catch (...) {
        
    }
}

static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

static bool readToken(string& tok) {
    return (cin >> tok) ? true : false;
}

static long long parseLLStrict(const string& s, bool& ok) {
    ok = false;
    if (s.empty()) return 0;
    int i = 0;
    bool neg = false;
    if (s[0] == '-') {
        neg = true;
        i = 1;
    }
    if (i == (int)s.size()) return 0;
    long long val = 0;
    for (; i < (int)s.size(); i++) {
        unsigned char c = (unsigned char)s[i];
        if (!isdigit(c)) return 0;
        int d = s[i] - '0';
        if (val > (LLONG_MAX - d) / 10) return 0;
        val = val * 10 + d;
    }
    ok = true;
    return neg ? -val : val;
}

static int readIntFromCin(int lo, int hi, const string& ctx) {
    string tok;
    if (!readToken(tok)) finish(_pe, "unexpected eof while reading " + ctx);
    bool ok = false;
    long long x = parseLLStrict(tok, ok);
    if (!ok) finish(_pe, "non-integer token while reading " + ctx);
    if (x < lo || x > hi) finish(_pe, "out of range while reading " + ctx);
    return (int)x;
}

static vector<int> bfsMultiSource(int n, const vector<vector<int>>& adj, const vector<int>& sources) {
    const int INF = 1e9;
    vector<int> dist(n + 1, INF);
    deque<int> q;
    for (int s : sources) {
        if (s < 1 || s > n) continue;
        if (dist[s] == 0) continue;
        dist[s] = 0;
        q.push_back(s);
    }
    while (!q.empty()) {
        int v = q.front();
        q.pop_front();
        int nd = dist[v] + 1;
        for (int to : adj[v]) {
            if (dist[to] > nd) {
                dist[to] = nd;
                q.push_back(to);
            }
        }
    }
    return dist;
}

static bool isNeighbor(const vector<vector<int>>& adj, int u, int v) {
    for (int to : adj[u]) if (to == v) return true;
    return false;
}

static vector<int> expandedSources(int n, const vector<vector<int>>& adj, const array<int, 3>& bees) {
    vector<char> used(n + 1, 0);
    vector<int> src;
    src.reserve(16);
    for (int i = 0; i < 3; i++) {
        int b = bees[i];
        if (b >= 1 && b <= n && !used[b]) {
            used[b] = 1;
            src.push_back(b);
        }
        if (b >= 1 && b <= n) {
            for (int to : adj[b]) {
                if (!used[to]) {
                    used[to] = 1;
                    src.push_back(to);
                }
            }
        }
    }
    return src;
}

static int pickNastyaStart(int n,
                           const vector<vector<int>>& adj,
                           const array<int, 3>& bees) {
    vector<char> occupied(n + 1, 0);
    for (int b : bees) if (b >= 1 && b <= n) occupied[b] = 1;

    vector<int> src0;
    src0.reserve(3);
    for (int b : bees) src0.push_back(b);
    vector<int> dist0 = bfsMultiSource(n, adj, src0);

    vector<int> src1 = expandedSources(n, adj, bees);
    vector<int> dist1 = bfsMultiSource(n, adj, src1);

    int bestV = -1;
    int bestD1 = -1, bestD0 = -1, bestDeg = -1;

    for (int v = 1; v <= n; v++) {
        if (occupied[v]) continue;
        int d1 = dist1[v];
        int d0 = dist0[v];
        int dg = (int)adj[v].size();
        if (bestV == -1 ||
            d1 > bestD1 ||
            (d1 == bestD1 && d0 > bestD0) ||
            (d1 == bestD1 && d0 == bestD0 && dg > bestDeg) ||
            (d1 == bestD1 && d0 == bestD0 && dg == bestDeg && v < bestV)) {
            bestV = v;
            bestD1 = d1;
            bestD0 = d0;
            bestDeg = dg;
        }
    }
    if (bestV == -1) finish(_fail, "internal: no valid start for Nastya");
    return bestV;
}

static int pickNastyaMove(int n,
                          const vector<vector<int>>& adj,
                          int curNastya,
                          const array<int, 3>& bees) {
    if (curNastya < 1 || curNastya > n) finish(_fail, "internal: Nastya out of range");
    const auto& nbrs = adj[curNastya];
    if (nbrs.empty()) finish(_fail, "internal: Nastya has no legal move");

    vector<int> src0;
    src0.reserve(3);
    for (int b : bees) src0.push_back(b);
    vector<int> dist0 = bfsMultiSource(n, adj, src0);

    vector<int> src1 = expandedSources(n, adj, bees);
    vector<int> dist1 = bfsMultiSource(n, adj, src1);

    int bestV = -1;
    int bestD1 = -1, bestD0 = -1, bestDeg = -1;

    for (int v : nbrs) {
        int d1 = dist1[v];
        int d0 = dist0[v];
        int dg = (int)adj[v].size();
        if (bestV == -1 ||
            d1 > bestD1 ||
            (d1 == bestD1 && d0 > bestD0) ||
            (d1 == bestD1 && d0 == bestD0 && dg > bestDeg) ||
            (d1 == bestD1 && d0 == bestD0 && dg == bestDeg && v < bestV)) {
            bestV = v;
            bestD1 = d1;
            bestD0 = d0;
            bestDeg = dg;
        }
    }
    if (bestV == -1) finish(_fail, "internal: no move picked for Nastya");
    return bestV;
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

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

    int n = inf.readInt(4, 5000, "n");
    int m = inf.readInt(n, 3 * n, "m");

    vector<pair<int, int>> edges;
    edges.reserve(m);
    vector<vector<int>> adj(n + 1);

    auto addAdjUnique = [&](int u, int v) {
        for (int to : adj[u]) if (to == v) return;
        adj[u].push_back(v);
    };

    for (int i = 0; i < m; i++) {
        int u = inf.readInt(1, n, "u");
        int v = inf.readInt(1, n, "v");
        edges.push_back({u, v});
        addAdjUnique(u, v);
        addAdjUnique(v, u);
    }

    query_limit = n;
    log_metrics(); 

    
    cout << n << ' ' << m << '\n';
    for (auto& e : edges) {
        cout << e.first << ' ' << e.second << '\n';
    }
    cout.flush();

    const long long hard_cap = max(200000LL, 10LL * query_limit);

    
    array<int, 3> bees;
    bees[0] = readIntFromCin(1, n, "initial bee 1");
    bees[1] = readIntFromCin(1, n, "initial bee 2");
    bees[2] = readIntFromCin(1, n, "initial bee 3");

    int nastya = pickNastyaStart(n, adj, bees);
    if (nastya == bees[0] || nastya == bees[1] || nastya == bees[2]) {
        finish(_fail, "internal: Nastya started on a bee vertex");
    }

    cout << nastya << '\n';
    cout.flush();

    for (int move = 1; move <= n; move++) {
        array<int, 3> nextBees;
        nextBees[0] = readIntFromCin(1, n, "bee move vertex 1");
        nextBees[1] = readIntFromCin(1, n, "bee move vertex 2");
        nextBees[2] = readIntFromCin(1, n, "bee move vertex 3");

        
        for (int i = 0; i < 3; i++) {
            int from = bees[i];
            int to = nextBees[i];
            if (to == from) continue;
            if (!isNeighbor(adj, from, to)) {
                finish(_pe, "illegal bee move (not adjacent)");
            }
        }
        bees = nextBees;

        queries++;
        if (queries > hard_cap) finish(_pe, "too many queries (hard cap exceeded)");

        
        if (bees[0] == nastya || bees[1] == nastya || bees[2] == nastya) {
            finish(_ok, "caught Nastya after bees move");
        }

        
        int nextNastya = pickNastyaMove(n, adj, nastya, bees);
        if (!isNeighbor(adj, nastya, nextNastya)) {
            finish(_fail, "internal: picked non-adjacent Nastya move");
        }
        nastya = nextNastya;

        cout << nastya << '\n';
        cout.flush();

        
        if (bees[0] == nastya || bees[1] == nastya || bees[2] == nastya) {
            finish(_ok, "caught Nastya after Nastya move");
        }
    }

    finish(_wa, "not caught within n moves");
}


Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

struct Builder {
    int targetN;
    int curN;
    vector<int> deg;
    vector<pair<int,int>> edges;
    vector<int> frontier;
    vector<char> sealed;
    unordered_set<long long> exist;

    explicit Builder(int targetN_) : targetN(targetN_), curN(0) {
        deg.assign(targetN + 1, 0);
        edges.reserve(3 * targetN + 5);
        sealed.reserve(3 * targetN + 5);
        frontier.reserve(3 * targetN + 5);
        exist.reserve((size_t)(6 * targetN + 100));
        exist.max_load_factor(0.7f);
    }

    static long long keyOf(int u, int v) {
        if (u > v) swap(u, v);
        return 1LL * u * 100000LL + v;
    }

    int newVertex() {
        if (curN >= targetN) quitf(_fail, "internal: exceeded targetN");
        return ++curN;
    }

    int addEdge(int u, int v) {
        if (u == v) quitf(_fail, "loop edge attempted");
        if (u < 1 || v < 1 || u > targetN || v > targetN) quitf(_fail, "vertex out of range");
        long long k = keyOf(u, v);
        if (exist.find(k) != exist.end()) {
            quitf(_fail, "duplicate edge attempted: %d %d", u, v);
        }
        exist.insert(k);
        edges.push_back({u, v});
        sealed.push_back(0);
        deg[u]++, deg[v]++;
        if (deg[u] > 3 || deg[v] > 3) quitf(_fail, "degree exceeded 3");
        return (int)edges.size() - 1;
    }

    bool isAttachableEdge(int eid) const {
        if (eid < 0 || eid >= (int)edges.size()) return false;
        if (sealed[eid]) return false;
        int u = edges[eid].first;
        int v = edges[eid].second;
        return deg[u] == 2 && deg[v] == 2;
    }

    bool isAttachableEdgeExcluding(int eid, int ex1, int ex2) const {
        if (!isAttachableEdge(eid)) return false;
        int u = edges[eid].first;
        int v = edges[eid].second;
        if (u == ex1 || u == ex2 || v == ex1 || v == ex2) return false;
        return true;
    }

    int takeAnyAttachableEdge(int ex1 = -1, int ex2 = -1) {
        for (int it = 0; it < 2000 && !frontier.empty(); it++) {
            int idx = rnd.next(0, (int)frontier.size() - 1);
            int eid = frontier[idx];
            frontier[idx] = frontier.back();
            frontier.pop_back();
            if (isAttachableEdgeExcluding(eid, ex1, ex2)) {
                sealed[eid] = 1;
                return eid;
            }
        }
        for (int eid = 0; eid < (int)edges.size(); eid++) {
            if (isAttachableEdgeExcluding(eid, ex1, ex2)) {
                sealed[eid] = 1;
                return eid;
            }
        }
        quitf(_fail, "no attachable edge found");
        return -1;
    }

    void addBaseCycle(int len) {
        vector<int> v(len);
        for (int i = 0; i < len; i++) v[i] = newVertex();
        for (int i = 0; i < len; i++) {
            int a = v[i];
            int b = v[(i + 1) % len];
            int eid = addEdge(a, b);
            frontier.push_back(eid);
        }
    }

    vector<int> attachPentagonOnSealedEdge(int eidSealed) {
        int u = edges[eidSealed].first;
        int v = edges[eidSealed].second;
        if (deg[u] != 2 || deg[v] != 2) quitf(_fail, "attachPentagon: endpoints not degree 2");
        int a = newVertex();
        int b = newVertex();
        int c = newVertex();
        int e1 = addEdge(v, a);
        int e2 = addEdge(a, b); 
        int e3 = addEdge(b, c); 
        int e4 = addEdge(c, u);
        (void)e1; (void)e4;
        frontier.push_back(e2);
        frontier.push_back(e3);
        return {e2, e3};
    }

    vector<int> attachSquareOnSealedEdge(int eidSealed) {
        int u = edges[eidSealed].first;
        int v = edges[eidSealed].second;
        if (deg[u] != 2 || deg[v] != 2) quitf(_fail, "attachSquare: endpoints not degree 2");
        int x = newVertex();
        int y = newVertex();
        int e1 = addEdge(v, x);
        int e2 = addEdge(x, y); 
        int e3 = addEdge(y, u);
        (void)e1; (void)e3;
        frontier.push_back(e2);
        return {e2};
    }

    vector<int> attachTriangleOnSealedEdge(int eidSealed) {
        int u = edges[eidSealed].first;
        int v = edges[eidSealed].second;
        if (deg[u] != 2 || deg[v] != 2) quitf(_fail, "attachTriangle: endpoints not degree 2");
        int w = newVertex();
        addEdge(u, w);
        addEdge(v, w);
        return {};
    }

    void buildRandom(int squarePct, int branchPct, bool preferPentagons) {
        if (targetN == 4) {
            addBaseCycle(4);
            return;
        }
        if (targetN < 4) quitf(_fail, "n must be >= 4");

        if (targetN >= 5) addBaseCycle(5);
        else addBaseCycle(4);

        int tail = takeAnyAttachableEdge();
        while (curN < targetN) {
            if (!isAttachableEdge(tail)) {
                tail = takeAnyAttachableEdge();
            } else {
                sealed[tail] = 1;
            }

            int remaining = targetN - curN;
            vector<int> candidates;

            if (remaining == 1) {
                candidates = attachTriangleOnSealedEdge(tail);
            } else if (remaining == 2) {
                candidates = attachSquareOnSealedEdge(tail);
            } else {
                bool makeSquare = false;
                if (!preferPentagons && remaining >= 2) {
                    int roll = rnd.next(0, 99);
                    if (roll < squarePct) makeSquare = true;
                }
                if (makeSquare && remaining == 3) makeSquare = false;
                if (makeSquare) candidates = attachSquareOnSealedEdge(tail);
                else candidates = attachPentagonOnSealedEdge(tail);
            }

            if (!candidates.empty()) {
                tail = candidates[rnd.next(0, (int)candidates.size() - 1)];
            }

            if (branchPct > 0 && curN < targetN && !candidates.empty()) {
                int roll = rnd.next(0, 99);
                if (roll < branchPct) {
                    int tu = edges[tail].first;
                    int tv = edges[tail].second;
                    int rem2 = targetN - curN;
                    if (rem2 >= 3) {
                        int beid = takeAnyAttachableEdge(tu, tv);
                        attachPentagonOnSealedEdge(beid);
                    }
                }
            }
        }

        for (int i = 1; i <= curN; i++) {
            if (deg[i] < 1 || deg[i] > 3) quitf(_fail, "invalid degree on vertex %d: %d", i, deg[i]);
        }
    }
};

static void outputGraph(int n, const vector<pair<int,int>>& edges) {
    cout << n << " " << (int)edges.size() << "\n";
    for (auto &e : edges) cout << e.first << " " << e.second << "\n";
}

int main(int argc, char** argv) {
    registerGen(argc, argv, 1);

    string mode = opt<string>("mode", "non");
    int seed = atoi(argv[1]);

    int forcedN = opt<int>("n", 0);
    int targetN;
    if (forcedN > 0) targetN = forcedN;
    else {
        if (seed == 1) targetN = 4;
        else if (seed == 2) targetN = 5;
        else if (seed == 3) targetN = 8;
        else targetN = (mode == "adp" ? 5000 : 5000);
    }

    targetN = max(4, min(5000, targetN));

    if (forcedN == 0 && seed == 1) {
        vector<pair<int,int>> edges;
        edges.push_back({1, 2});
        edges.push_back({2, 3});
        edges.push_back({3, 4});
        edges.push_back({4, 1});
        outputGraph(4, edges);
        return 0;
    }
    if (forcedN == 0 && seed == 2) {
        vector<pair<int,int>> edges;
        edges.push_back({1, 2});
        edges.push_back({2, 3});
        edges.push_back({3, 4});
        edges.push_back({4, 5});
        edges.push_back({5, 1});
        outputGraph(5, edges);
        return 0;
    }
    if (forcedN == 0 && seed == 3) {
        vector<pair<int,int>> edges;
        
        
        edges.push_back({1, 2});
        edges.push_back({2, 3});
        edges.push_back({3, 4});
        edges.push_back({4, 5});
        edges.push_back({5, 1});
        edges.push_back({2, 6});
        edges.push_back({6, 7});
        edges.push_back({7, 8});
        edges.push_back({8, 1});
        outputGraph(8, edges);
        return 0;
    }

    int squarePct = opt<int>("square", mode == "adp" ? 2 : 12);
    int branchPct = opt<int>("branch", mode == "adp" ? 0 : 10);

    squarePct = max(0, min(60, squarePct));
    branchPct = max(0, min(60, branchPct));

    Builder b(targetN);

    if (mode == "adp") {
        
        b.buildRandom(squarePct, branchPct, true);
    } else if (mode == "non") {
        
        b.buildRandom(squarePct, branchPct, false);
    } else {
        quitf(_fail, "unknown mode: %s", mode.c_str());
    }

    outputGraph(b.curN, b.edges);
    return 0;
}