#include <cassert> #include <cmath> #include <cstdint> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <functional> #include <iostream> #include <limits> #include <map> #include <numeric> #include <queue> #include <random> #include <set> #include <sstream> #include <string> #include <unordered_map> #include <unordered_set> #include <utility> #include <vector> using namespace std; using Int = long long; template <class T1, class T2> ostream &operator<<(ostream &os, const pair<T1, T2> &a) { return os << "(" << a.first << ", " << a.second << ")"; }; template <class T> ostream &operator<<(ostream &os, const vector<T> &as) { const int sz = as.size(); os << "["; for (int i = 0; i < sz; ++i) { if (i >= 256) { os << ", ..."; break; } if (i > 0) { os << ", "; } os << as[i]; } return os << "]"; } template <class T> void pv(T a, T b) { for (T i = a; i != b; ++i) cerr << *i << " "; cerr << endl; } template <class T> bool chmin(T &t, const T &f) { if (t > f) { t = f; return true; } return false; } template <class T> bool chmax(T &t, const T &f) { if (t < f) { t = f; return true; } return false; } #define COLOR(s) ("\x1b[" s "m") int I; map<vector<int>, int> tr; void init() { I = 0; tr.clear(); } int id(const vector<int> &seq) { auto it = tr.find(seq); if (it != tr.end()) return it->second; return tr[seq] = I++; } struct Tree { int n; vector<vector<int>> graph; void init(int n_) { n = n_; graph.assign(n, {}); } void ae(int u, int v) { graph[u].push_back(v); graph[v].push_back(u); } vector<int> dp; void dfs(int u, int p) { vector<int> seq; for (const int v : graph[u]) if (p != v) { dfs(v, u); seq.push_back(dp[v]); } sort(seq.begin(), seq.end()); dp[u] = id(seq); } void run(int r) { dp.assign(n, -1); dfs(r, -1); } } T[2]; int N; vector<int> A, B, C; int H, W; char S[30][30]; bool inside(int x, int y) { return (0 <= x && x < H && 0 <= y && y < W && S[x][y] == '#'); } int K; int ids[30][30]; vector<int> X, Y; vector<int> ans; void recover(int u0, int p0, int u1, int p1) { ans[u0] = u1; vector<int> vs0, vs1; for (const int v : T[0].graph[u0]) if (v != p0) vs0.push_back(v); for (const int v : T[1].graph[u1]) if (v != p1) vs1.push_back(v); assert(vs0.size() == vs1.size()); for (const int v0 : vs0) { for (int i = 0; i < (int)vs1.size(); ++i) { const int v1 = vs1[i]; if (T[0].dp[v0] == T[1].dp[v1]) { recover(v0, u0, v1, u1); vs1.erase(vs1.begin() + i); break; } } } assert(!vs1.size()); } bool solve() { init(); K = 0; memset(ids, ~0, sizeof(ids)); X.clear(); Y.clear(); for (int x = 0; x < H; ++x) for (int y = 0; y < W; ++y) if (inside(x, y)) { ids[x][y] = K++; X.push_back(x); Y.push_back(y); } T[1].init(K); for (int x = 0; x < H; ++x) for (int y = 0; y < W; ++y) if (inside(x, y)) { if (inside(x + 1, y)) T[1].ae(ids[x][y], ids[x + 1][y]); if (inside(x, y + 1)) T[1].ae(ids[x][y], ids[x][y + 1]); } int n = N; for (int i = 0; i < N - 1; ++i) n += (C[i] - 1); if (n != K) return false; T[0].init(n); n = N; for (int i = 0; i < N - 1; ++i) { int u = A[i]; for (int c = 1; c < C[i]; ++c) { const int v = n++; T[0].ae(u, v); u = v; } T[0].ae(u, B[i]); } T[0].run(0); for (int r = 0; r < K; ++r) { T[1].run(r); if (T[0].dp[0] == T[1].dp[r]) { ans.resize(K, -1); recover(0, -1, r, -1); puts("Yes"); for (int u = 0; u < N; ++u) { printf("%d %d\n", X[ans[u]] + 1, Y[ans[u]] + 1); } return true; } } return false; } int main() { for (int numCases; ~scanf("%d", &numCases); ) { for (int caseId = 1; caseId <= numCases; ++caseId) { scanf("%d", &N); A.resize(N - 1); B.resize(N - 1); C.resize(N - 1); for (int i = 0; i < N - 1; ++i) { scanf("%d%d%d", &A[i], &B[i], &C[i]); --A[i]; --B[i]; } scanf("%d%d", &H, &W); for (int x = 0; x < H; ++x) { scanf("%s", S[x]); } const bool res = solve(); if (!res) { puts("No"); } } #ifndef LOCAL break; #endif } return 0; }