#include <fstream>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
#include <cassert>

using namespace std;

ifstream in("zoo.in");
ofstream out("zoo.out");

int n, m;

vector<vector<int> > edges;
vector<vector<int> > paths;
vector<int> fromV;
vector<int> toV;

vector<int> walk(int from, int to, vector<int> path, bool rev) {
    int v = 0;

    if (rev) {
        swap(to, from);
        v = 1;
    }
    int cur = from;
    
    vector<int> res;
    if (cur != edges[path[0]][v]) {
        res.push_back(path[0]);
        return res;
    }
    cur = edges[path[0]][1 ^ v];
    size_t i = 0;
    while (++i < path.size()) {
        if (cur != edges[path[i]][v]) {
            res.push_back(path[i]);
            res.push_back(path[i - 1]);
            return res;
        }
        cur = edges[path[i]][1 ^ v];
    }
    if (cur != to) {
        res.push_back(path.back());
        return res;
    }
    return vector<int>();
}

vector<int> search_cond(int from, int to, vector<int> path) {
    vector<int> cond1 = walk(from, to, path, false);
    reverse(path.begin(), path.end());
    vector<int> cond2 = walk(from, to, path, true);
    reverse(path.begin(), path.end());

    vector<int> ans;
    for (size_t i = 0; i < cond1.size(); i++)
        for (size_t j = 0; j < cond2.size(); j++)
            if (cond1[i] == cond2[j]) {
                ans.push_back(cond1[i]);
            }
    if (ans.size() > 0) {
        return ans;
    }
    ans = cond1;
    if (cond2.size() > 0)
        ans.insert(ans.end(), cond2.begin(), cond2.end());
    return ans;
}

bool check(int v, int u) {
    swap(edges[v], edges[u]);
    bool f = true;
    int ti = 0;
    vector<int> used(n);
    for (size_t q = 0; q < paths.size(); q++) {
        vector<int> path = paths[q];
        int cur = fromV[q];
        size_t i = -1;
        ti++;
        used[cur] = ti;
        while (++i < path.size()) {
            if (cur != edges[path[i]][0]) {
                f = false;
                break;
            }
            cur = edges[path[i]][1];
            if (used[cur] == ti) {
                f = false;
                break;
            }
            used[cur] = ti;
        }
        if (cur != toV[q]) {
            f = false;
        }
        if (!f) break;
    }
    swap(edges[v], edges[u]);
    return f;
}

bool check(vector<int> res) {
    for (size_t i = 0; i < res.size(); i++)
        for (size_t j = i + 1; j < res.size(); j++) {
            if (check(res[i], res[j])) {
                out << res[i] + 1 << " " << res[j] + 1<< endl;
                return true;
            }
        }
    return false;
}

int main(){
    in >> n >> m;
    edges.resize(m);
    for (int i = 0; i < m; i++) {
        int to, from, num;
        in >> from >> to >> num;
        num--, from--, to--;
        edges[num].push_back(from), edges[num].push_back(to);
    }

    int k;
    in >> k;
    paths.resize(k);
    fromV.resize(k), toV.resize(k);
    for (int i = 0; i < k; i++) {
        int len;
        in >> len >> fromV[i] >> toV[i];
        fromV[i]--, toV[i]--;
        paths[i].resize(len);
        for (int j = 0; j < len; j++) {
            in >> paths[i][j];
            paths[i][j]--;
        }
    }

    set<int> cond;
    for (size_t i = 0; i < paths.size(); i++) {
        vector<int> res = search_cond(fromV[i], toV[i], paths[i]);
        if (res.size() < 4) {
            bool f = true;
            for (size_t i = 0; i < res.size(); i++) 
                if (cond.count(res[i])) {
                    f = false;
                }
            if (f) {
                for (size_t i = 0; i < res.size(); i++) 
                    cond.insert(res[i]);
            }
        } else {
            if (check(res)) return 0;
        }
    }
    vector<int> res(cond.begin(), cond.end());
    check(res);
}
