Problem: abc305_f
Difficulty: easy
Categories: graph
Time limit: 2000 ms, memory limit: 1024 MB

### Problem Statement

This is an **interactive problem** (where your program and the judge program interact through Standard Input and Output).

There is a simple connected undirected graph with $N$ vertices and $M$ edges.
The vertices are numbered with integers from $1$ to $N$.

Initially, you are at vertex $1$.
Repeat moving to an adjacent vertex at most $2N$ times to reach vertex $N$.

Here, you do not initially know all edges of the graph, but you will be informed of the vertices adjacent to the vertex you are at.

### Constraints

* $2\leq N\leq100$
* $N-1\leq M\leq\dfrac{N(N-1)}2$
* The graph is simple and connected.
* All input values are integers.

### Input and Output

First, receive the number of vertices $N$ and the number of edges $M$ in the graph from Standard Input:

```
$N$ $M$
```

Next, you get to repeat the operation described in the problem statement at most $2N$ times against the judge.

At the beginning of each operation, the vertices adjacent to the vertex you are currently at are given from Standard Input in the following format:

```
$k$ $v _ 1$ $v _ 2$ $\ldots$ $v _ k$
```

Here, $v _ i\ (1\leq i\leq k)$ are integers between $1$ and $N$ such that $v _ 1\lt v _ 2\lt\cdots\lt v _ k$.

Choose one of $v _ i\ (1\leq i\leq k)$ and print it to Standard Output in the following format:

```
$v _ i$
```

After this operation, you will be at vertex $v _ i$.

If you perform more than $2N$ operations or print invalid output, the judge will send `-1` to Standard Input.

If the destination of a move is vertex $N$, the judge will send `OK` to Standard Input and terminate.

When receiving `-1` or `OK`, immediately terminate the program.

### Notes

* **In each output, insert a newline at the end and flush Standard Output. Otherwise, the verdict may be TLE.**
* **The verdict will be indeterminate if the program prints invalid output or quits prematurely in the middle of the interaction.**
* Terminate the program immediately after reaching vertex $N$. Otherwise, the verdict will be indeterminate.
* **The judge for this problem is adaptive. This means that the graph may change without contradicting the constraints or previous outputs.**

### Sample Interaction

In the following sample interaction, we have $N=4$, $M=5$, and the graph in the figure below.

![](https://img.atcoder.jp/abc305/ae6ce1b3c8e950777761893a567c4d11.png)

| Input | Output | Description |
| --- | --- | --- |
| `4 5` |  | $N$ and $M$ are given. |
| `2 2 3` |  | You start at vertex $1$. The vertices adjacent to vertex $1$ are given. |
|  | `3` | You choose to go to vertex $v _ 2=3$. |
|
| `3 1 2 4` |  | The vertices adjacent to vertex $3$ are given. |
|  | `2` | You choose to go to vertex $v _ 2=2$. |
|
| `3 1 3 4` |  | The vertices adjacent to vertex $2$ are given. |
|  | `4` | You choose to go to vertex $v _ 3=4$. |
|
| `OK` |  | Since you have reached vertex $4$ within $8(=2\times4)$ moves, `OK` is passed. |

You will be judged as correct if you immediately terminate the program after receiving `OK`.

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

using namespace std;


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





void log_metrics() {
    
    
    if (tout.is_open()) {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    }
}





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

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

    
    int N = inf.readInt();
    int M = inf.readInt();

    
    query_limit = 2LL * N;

    
    log_metrics();

    
    vector<vector<int>> adj(N + 1);
    for (int i = 0; i < M; i++) {
        int u = inf.readInt();
        int v = inf.readInt();
        if (u >= 1 && u <= N && v >= 1 && v <= N) {
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
    }

    
    for (int i = 1; i <= N; i++) {
        sort(adj[i].begin(), adj[i].end());
    }

    
    
    cout << N << " " << M << endl;
    
    int curr = 1;

    
    if (curr == N) {
        cout << "OK" << endl;
        finish(_ok, "Start is goal");
    }

    
    while (true) {
        
        
        
        if (queries >= query_limit) {
            cout << "-1" << endl;
            finish(_wa, "Move limit exceeded (" + to_string(query_limit) + ")");
        }

        
        const vector<int>& neighbors = adj[curr];
        cout << neighbors.size();
        for (int v : neighbors) {
            cout << " " << v;
        }
        cout << endl; 

        
        
        string token;
        if (!(cin >> token)) {
            finish(_wa, "Unexpected EOF reading contestant output");
        }

        
        int next_v = -1;
        try {
            size_t pos;
            next_v = stoi(token, &pos);
            
            if (pos != token.size()) {
                cout << "-1" << endl;
                finish(_wa, "Invalid output format: expected integer, got '" + token + "'");
            }
        } catch (...) {
            
            cout << "-1" << endl;
            finish(_wa, "Invalid output format: expected integer, got '" + token + "'");
        }

        
        bool valid_move = false;
        for (int v : neighbors) {
            if (v == next_v) {
                valid_move = true;
                break;
            }
        }

        if (!valid_move) {
            cout << "-1" << endl;
            finish(_wa, "Invalid move: vertex " + to_string(next_v) + " is not adjacent to " + to_string(curr));
        }

        
        curr = next_v;
        queries++;

        
        if (queries % 10 == 0) {
            log_metrics();
        }

        
        if (curr == N) {
            cout << "OK" << endl;
            finish(_ok, "Reached goal vertex N");
        }
    }

    return 0;
}


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() {
    
    
    if (query_limit > 0) {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    }
}


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



vector<vector<int>> adj;

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

    
    int N = inf.readInt();
    int M = inf.readInt();
    
    
    query_limit = 2LL * N;

    
    
    
    
    bool is_adaptive = inf.seekEof();

    adj.assign(N + 1, vector<int>());

    if (!is_adaptive) {
        
        for (int i = 0; i < M; ++i) {
            int u = inf.readInt();
            int v = inf.readInt();
            
            if (u < 1 || u > N || v < 1 || v > N) {
                finish(_fail, "Invalid vertex index in static input");
            }
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
    } else {
        
        
        
        
        rnd.setSeed(N * 72341LL + M * 91238LL + 42LL);

        
        
        
        
        vector<int> nodes(N);
        iota(nodes.begin(), nodes.end(), 1);
        shuffle(nodes.begin(), nodes.end()); 

        set<pair<int, int>> edges;
        auto add_edge_internal = [&](int u, int v) {
            if (u > v) swap(u, v);
            if (u == v) return false;
            if (edges.count({u, v})) return false;
            edges.insert({u, v});
            adj[u].push_back(v);
            adj[v].push_back(u);
            return true;
        };

        
        for (int i = 1; i < N; ++i) {
            int parent = nodes[rnd.next(i)];
            add_edge_internal(nodes[i], parent);
        }

        
        long long current_m = N - 1;
        int fails = 0;
        
        
        while (current_m < M && fails < 2000) {
            int u = rnd.next(1, N);
            int v = rnd.next(1, N);
            if (add_edge_internal(u, v)) {
                current_m++;
                fails = 0;
            } else {
                fails++;
            }
        }
        
        
        if (current_m < M) {
            
            for (int i = 1; i <= N && current_m < M; ++i) {
                for (int j = i + 1; j <= N && current_m < M; ++j) {
                     if (add_edge_internal(i, j)) {
                         current_m++;
                     }
                }
            }
        }
    }

    
    
    cout << N << " " << M << endl;

    
    int curr = 1;

    while (true) {
        
        if (curr == N) {
            cout << "OK" << endl;
            finish(_ok, "Reached N");
        }

        
        
        
        
        if (queries >= query_limit) {
            cout << "-1" << endl;
            finish(_wa, "Too many moves");
        }

        
        vector<int>& neighbors = adj[curr];
        sort(neighbors.begin(), neighbors.end());

        
        cout << neighbors.size();
        for (int v : neighbors) {
            cout << " " << v;
        }
        cout << endl;

        
        int next_node;
        if (!(cin >> next_node)) {
            finish(_wa, "Contestant closed stream or invalid output format");
        }

        
        bool valid = false;
        for (int v : neighbors) {
            if (v == next_node) {
                valid = true;
                break;
            }
        }

        if (!valid) {
            
            cout << "-1" << endl;
            finish(_wa, "Invalid move: destination not adjacent");
        }

        
        curr = next_node;
        queries++;
        
        
        if (queries % 10 == 0) log_metrics();
    }

    return 0;
}


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

using namespace std;

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

    
    string mode = opt<string>("mode", "non"); 
    int n_arg = opt<int>("N", -1);
    int m_arg = opt<int>("M", -1);

    
    long long seed_val = 0;
    try {
        if (argc > 1) seed_val = stoll(string(argv[1]));
    } catch (...) {}

    int N, M;
    bool manual_params = (n_arg != -1 || m_arg != -1);

    
    if (!manual_params && seed_val == 1) {
        N = 2; M = 1;
    } else if (!manual_params && seed_val == 2) {
        N = 100; M = 99; 
    } else if (!manual_params && seed_val == 3) {
        N = 100; M = 100 * 99 / 2; 
    } else {
        
        if (n_arg != -1) N = n_arg;
        else N = rnd.next(2, 100);

        long long min_m = N - 1;
        long long max_m = (long long)N * (N - 1) / 2;

        if (m_arg != -1) {
            M = m_arg;
            if (M < min_m) M = min_m;
            if (M > max_m) M = max_m;
        } else {
            
            int t = rnd.next(100);
            if (t < 50) {
                
                M = rnd.next((int)min_m, (int)min(max_m, min_m + 2 * N));
            } else if (t < 80) {
                
                M = rnd.next((int)max(min_m, max_m - 2 * N), (int)max_m);
            } else {
                
                M = rnd.next((int)min_m, (int)max_m);
            }
        }
    }

    
    
    if (mode == "adp") {
        cout << N << " " << M << endl;
        return 0;
    }

    
    
    
    
    

    set<pair<int, int>> edges_set;
    vector<pair<int, int>> edges;

    auto add_edge = [&](int u, int v) {
        if (u > v) swap(u, v);
        if (u != v && !edges_set.count({u, v})) {
            edges_set.insert({u, v});
            edges.push_back({u, v});
        }
    };

    
    int type = rnd.next(3);
    if (!manual_params && seed_val == 2) type = 0; 
    if (!manual_params && seed_val == 3) type = 2; 

    if (type == 0) {
        
        
        vector<int> path_nodes;
        path_nodes.push_back(0);
        if (N > 2) {
            vector<int> mids(N - 2);
            iota(mids.begin(), mids.end(), 1); 
            shuffle(mids.begin(), mids.end());
            path_nodes.insert(path_nodes.end(), mids.begin(), mids.end());
        }
        if (N > 1) path_nodes.push_back(N - 1);
        
        for (size_t i = 0; i < path_nodes.size() - 1; ++i) {
            add_edge(path_nodes[i], path_nodes[i+1]);
        }
    } else if (type == 1) {
        
        vector<int> connected = {0};
        vector<int> remaining;
        for (int i = 1; i < N; ++i) remaining.push_back(i);
        shuffle(remaining.begin(), remaining.end());

        for (int u : remaining) {
            int v = connected[rnd.next(connected.size())];
            add_edge(u, v);
            connected.push_back(u);
        }
    } else {
        
        vector<int> nodes(N);
        iota(nodes.begin(), nodes.end(), 0);
        shuffle(nodes.begin(), nodes.end());
        for (int i = 1; i < N; ++i) {
            add_edge(nodes[i], nodes[rnd.next(i)]);
        }
    }

    
    int needed = M - (int)edges.size();
    long long total_pairs = (long long)N * (N - 1) / 2;
    
    if (needed > 0) {
        if (total_pairs - edges.size() < 2LL * needed) {
            
            vector<pair<int, int>> missing;
            for (int i = 0; i < N; ++i) {
                for (int j = i + 1; j < N; ++j) {
                    if (!edges_set.count({i, j})) {
                        missing.push_back({i, j});
                    }
                }
            }
            shuffle(missing.begin(), missing.end());
            for (int i = 0; i < needed; ++i) {
                add_edge(missing[i].first, missing[i].second);
            }
        } else {
            
            while ((int)edges.size() < M) {
                int u = rnd.next(0, N - 1);
                int v = rnd.next(0, N - 1);
                add_edge(u, v);
            }
        }
    }

    
    
    
    vector<int> label(N);
    label[0] = 1;
    label[N - 1] = N;
    if (N > 2) {
        vector<int> p;
        for (int i = 2; i <= N - 1; ++i) p.push_back(i);
        shuffle(p.begin(), p.end());
        int idx = 0;
        for (int i = 1; i < N - 1; ++i) label[i] = p[idx++];
    }

    
    cout << N << " " << M << endl;
    for (const auto& e : edges) {
        cout << label[e.first] << " " << label[e.second] << endl;
    }

    return 0;
}