#include using namespace std; using ll = long long; using ld = long double; using pii = pair; using vi = vector; using vvi = vector; #define rep(i, a, b) for(ll i = (a); i < (b); i++) #define all(x) begin(x),end(x) #define sz(x) (int)(x).size() void solve() { ll r, c; cin >> r >> c; vector> from(r, vector(c)), to(r, vector(c)); rep(i, 0, r) rep(ii, 0, c) cin >> from[i][ii]; rep(i, 0, r) rep(ii, 0, c) cin >> to[i][ii]; bool needPath = true; rep(i, 0, r) rep(ii, 0, c) if (from[i][ii] == '*' && to[i][ii] == '*') needPath = false; auto adj = [&](ll i, ll ii) { vector next; if (i + 1 < r) next.emplace_back(i+1, ii); if (ii + 1 < c) next.emplace_back(i, ii+1); if (i - 1 >= 0) next.emplace_back(i-1, ii); if (ii - 1 >= 0) next.emplace_back(i, ii-1); return next; }; auto getOrdering = [&](vector& start, vector>& map) { vector> seen(r, vector(c, false)); for(auto [x, y] : start) seen[x][y] = true; rep(i, 0, sz(start)) { auto [x1, y1] = start[i]; for (auto [x2, y2] : adj(x1, y1)) if (!seen[x2][y2] && map[x2][y2] == '*') { seen[x2][y2] = true; start.emplace_back(x2, y2); } } }; if (needPath) { queue start; vector> prev(r, vector(c, make_pair(-1, -1))); rep(i, 0, r) rep(ii, 0, c) if(from[i][ii] == '*') { start.emplace(i, ii); prev[i][ii].first = -2; } pii attachEnd, attachStart; bool foundEnd = false; for(; sz(start); start.pop()) { auto [i, ii] = start.front(); if (to[i][ii] == '*') { attachEnd = make_pair(i, ii); foundEnd = true; break; } for (auto [x, y] : adj(i, ii)) if (prev[x][y].first == -1 && from[x][y] != 'X'){ prev[x][y] = make_pair(i, ii); start.emplace(x, y); } } if (!foundEnd) { cout << "NO" << endl; return; } vector path(1, attachEnd); while(from[path.back().first][path.back().second] != '*') { path.push_back(prev[path.back().first][path.back().second]); } attachStart = path.back(); path.pop_back(); reverse(all(path)); path.pop_back(); vector fromOrdering; fromOrdering.push_back(attachStart); getOrdering(fromOrdering, from); vector toOrdering; toOrdering.push_back(attachEnd); getOrdering(toOrdering, to); reverse(all(fromOrdering)); fromOrdering.insert(end(fromOrdering), all(path)); path.insert(end(path), all(toOrdering)); assert(sz(fromOrdering) == sz(path)); cout << "YES" << endl; cout << sz(fromOrdering) << endl; rep(i, 0, sz(fromOrdering)) { cout << fromOrdering[i].first + 1 << " " << fromOrdering[i].second + 1 << " " << path[i].first + 1 << " " << path[i].second + 1 << endl; } } else { vector overlap; rep(i, 0, r) rep(ii, 0, c) if (from[i][ii] == '*' && to[i][ii] == '*') overlap.emplace_back(i, ii); vector fromOrdering(all(overlap)); vector toOrdering(all(overlap)); getOrdering(fromOrdering, from); getOrdering(toOrdering, to); fromOrdering.erase(begin(fromOrdering), next(begin(fromOrdering), sz(overlap))); toOrdering.erase(begin(toOrdering), next(begin(toOrdering), sz(overlap))); reverse(all(fromOrdering)); if (sz(fromOrdering) != sz(toOrdering)) exit(0); // NO OUTPUT cout << "YES" << endl; cout << sz(fromOrdering) << endl; rep(i, 0, sz(fromOrdering)) { cout << fromOrdering[i].first + 1 << " " << fromOrdering[i].second + 1 << " " << toOrdering[i].first + 1 << " " << toOrdering[i].second + 1 << endl; } } } int main() { cin.tie(0)->sync_with_stdio(0); cin.exceptions(cin.failbit); //ll t; cin >> t; while(t--) solve(); }