Problem:
Deciphering Characters
Image data which are left by a mysterious syndicate were discovered. 
You are requested to analyze the data.
The syndicate members used characters invented independently. 
A binary image corresponds to one character written in black ink on white paper.
Although you found many variant images that represent the same character, 
you discovered that you can judge whether or not two images represent the same character with the surrounding relation of connected components. We present some definitions as follows.  Here, we assume that white pixels fill outside of the given image.
White connected component
: A set of white pixels connected to each other horizontally or vertically (see below).
Black connected component
: A set of black pixels connected to each other horizontally, vertically, or diagonally (see below).
Connected component
: A white or a black connected component.
Background component
: The connected component including pixels outside of the image. Any white pixels on the periphery of the image are thus included in the background component.
connected
disconnected
connected
connected
Connectedness of white pixels
Connectedness of black pixels
Let
C
1
be a connected component in an image and
C
2
be another connected component in the same image with the opposite color.
Let's think of a modified image in which colors of all pixels not included in
C
1
nor
C
2
are changed to that of
C
2
. If neither
C
1
nor
C
2
is the background component, the color of the background component is changed to that of
C
2
. We say that
C
1
surrounds
C
2
in the original image when pixels in
C
2
are not included in the background component in the modified image. (see below)
Two images represent the same character if both of the following conditions are satisfied.
The two images have the same number of connected components.
Let
S
and
S'
be the sets of connected components of the two images.   A bijective function
f
:
S → S'
satisfying the following conditions exists.
For each connected component
C
that belongs to
S
,
f
(
C
) has the same color as
C
.
For each of
C
1
and
C
2
belonging to
S
,
f
(
C
1
) surrounds
f
(
C
2
) if and only if
C
1
surrounds
C
2
.
Let's see an example. Connected components in the images of the figure below has the following surrounding relations.
C
1
surrounds
C
2
.
C
2
surrounds
C
3
.
C
2
surrounds
C
4
.
C'
1
surrounds
C'
2
.
C'
2
surrounds
C'
3
.
C'
2
surrounds
C'
4
.
A bijective function defined as
f
(
C
i
) =
C'
i
for each connected component satisfies the conditions stated above.  Therefore, we can conclude that the two images represent the same character.
Make a program judging whether given two images represent the same character.
Input
The input consists of at most 200 datasets. The end of the input is represented by a line containing two zeros. Each dataset is formatted as follows.
image 1
image 2
Each image has the following format.
h
w
p
(1,1)
...
p
(1,
w
)
...
p
(
h
,1)
...
p
(
h
,
w
)
h
and
w
are the height an
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
      
#define FOR(i,a,b) for( ll i = (a); i < (ll)(b); i++ )
#define REP(i,n) FOR(i,0,n)
#define YYS(x,arr) for(auto& x:arr)
#define ALL(x) (x).begin(),(x).end()
#define SORT(x) sort( (x).begin(),(x).end() )
#define REVERSE(x) reverse( (x).begin(),(x).end() )
#define UNIQUE(x) (x).erase( unique( ALL( (x) ) ) , (x).end() )
#define PW(x) (1LL<<(x))
#define SZ(x) ((ll)(x).size())
#define SHOW(x) cout << #x << " = " << x << endl
#define SHOWA(x,n) for( int yui = 0; yui < n; yui++ ){ cout << x[yui] << " "; } cout << endl

#define pb emplace_back
#define fi first
#define se second

using namespace std;

typedef long double ld;
typedef long long int ll;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
typedef vector<ld> vd;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<vpl> gr;
typedef vector<vl> ml;
typedef vector<vd> md;
typedef vector<vi> mi;
     
const ll INF = (ll)1e9 + 10;
const ll INFLL = (ll)1e18 + 10;
const ld EPS = 1e-12;
const ll MOD = 1e9+7;
     
template<class T> T &chmin( T &a , const T &b ){ return a = min(a,b); }
template<class T> T &chmax( T &a , const T &b ){ return a = max(a,b); }
template<class T> inline T sq( T a ){ return a * a; }

ll in(){ long long int x; scanf( "%lld" , &x ); return x; }
char yuyushiki[1000010]; string stin(){ scanf( "%s" , yuyushiki ); return yuyushiki; }

// head

const int dx[] = { 1 , 0 , -1 , 0 , 1 , -1 , -1 , 1 };
const int dy[] = { 0 , -1 , 0 , 1 , -1 , -1 , 1 , 1 };
const int type[] = { 4 , 8 };
const char opp[] = { '#' , '.' };

const int N = 10;

ll A[N];
ll B[N];

vi G[100010];

int it = 0;

int n, m;

bool used[128][128];

string s[128];

bool isin( int y , int x ){
  return 0 <= y && y < n && 0 <= x && x < m;
}

void dfs2( int y , int x , int t , vpi &v ){
  // cout << y << " " << x << endl;
  used[y][x] = true;
  v.pb( y , x );
  REP( i , type[t] ){
    int ny = y + dy[i];
    int nx = x + dx[i];
    if( isin( ny , nx ) && !used[ny][nx] ){
      if( s[ny][nx] == opp[t] ){
        v.pb( ny , nx );
      } else {
        dfs2( ny , nx , t , v );
      }
    }
  }
}

int dfs( int y, int x , int t ){
  int cur = it++;
  vpi v(0);
  // cout << "---" << endl;
  dfs2( y , x , t , v );
  YYS( w , v ){
    if( !used[w.fi][w.se] ){
      G[cur].pb( dfs( w.fi , w.se , 1-t ) );
    }
  }
  return cur;
}

int get(){
  n = in();
  m = in();
  if( n == 0 && m == 0 ){
    return -1;
  }
  s[0] = string( m+2 , '.' );
  REP( i , n ){
    s[i+1] = "." + stin() + ".";
  }
  s[n+1] = string( m+2 , '.' );
  n += 2;
  m += 2;
  /*
  REP( i , n ){
    cout << s[i] << endl;
  }
  */
  REP( i , n ){
    REP( j , m ){
      used[i][j] = false;
    }
  }
  return dfs( 0 , 0 , 0 );
}

ll ha( int x , ll a , ll b ){
  ll res = a;
  vl v(0);
  YYS( w , G[x] ){
    v.pb( ha( w , a , b ) );
  }
  SORT( v );
  YYS( w , v ){
    res = ( res * a + w ) % MOD;
  }
  return ( res + b ) % MOD;
}

int main(){

  mt19937 mt(727272);
 
  REP( i , N ){
    A[i] = mt();
    B[i] = mt();
  }
  
  while( 1 ){
    REP( i , 100010 ){
      G[i].clear();
    }
    it = 0;
    int ra = get();
    if( ra == -1 ){
      break;
    }
    int rb = get();
    /*
    REP( i , it ){
      SHOWA( G[i] , SZ(G[i]) );
    }
    */
    bool ok = true;
    REP( i , N ){
      if( ha( ra , A[i] , B[i] ) != ha( rb , A[i] , B[i] ) ){
        ok = false;
        break;
      }
    }
    if( ok ){
      puts( "yes" );
    } else {
      puts( "no" );
    }
  }
  
  return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 6104
final_rank: 15

code_snippet: // C++ includes used for precompiling -*- C++ -*-
// Copyright (C) 2003-2013 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://w...content-available-to-author-only...u.org/licenses/>.
/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */
// 17.4.1.2 Headers
// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <unordered_set>

#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline void compress(vector<T> &a) {
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
}
template <class T>
T rand(T l, T r) {
    static mt19937 mt(random_device{}());
    // [l, r)
    if constexpr (is_integral_v<T>) {
        return uniform_int_distribution<T>(l, r - 1)(mt);
    } else if constexpr (is_floating_point_v<T>) {
        return uniform_real_distribution<T>(l, r)(mt);
    }
}
constexpr int INF = 1001001001;
constexpr ll llINF = 3000000000000000010;
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    // ax+by=gcd(|a|,|b|)
    if (a < 0 || b < 0) {
        ll d = extgcd(abs(a), abs(b), x, y);
        if (a < 0) x = -x;
        if (b < 0) y = -y;
        return d;
    }
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
template <class T>
vector<T> dijkstra(vector<vector<pair<int, T>>> &g, vector<int> start) {
    using P = pair<T, int>;
    vector<T> dp(g.size(), numeric_limits<T>::max());
    priority_queue<P, vector<P>, greater<P>> que;
    for (int s : start) {
        dp[s] = 0;
        que.push({0, s});
    }
    while (que.size()) {
        auto [d, v] = que.top();
        que.pop();
        if (dp[v] != d) continue;
        for (auto [u, c] : g[v]) {
            if (chmin(dp[u], d + c)) que.push({dp[u], u});
        }
    }
    return dp;
}

vector<int> BFS01(vector<vector<pair<int, int>>> &g, vector<int> start) {
    vector<int> dp(g.size(), numeric_limits<int>::max());
    deque<int> que;
    for (int s : start) {
        dp[s] = 0;
        que.push_front(s);
    }
    while (que.size()) {
        auto v = que.front();
        que.pop_front();
        for (auto [u, c] : g[v]) {
            if (chmin(dp[u], dp[v] + c)) {
                if (c == 0)
                    que.push_front(u);
                else
                    que.push_back(u);
            }
        }
    }
    return dp;
}
template <typename T, typename U>
inline istream &operator>>(istream &is, pair<T, U> &rhs) {
    return is >> rhs.first >> rhs.second;
}
template <typename T>
inline istream &operator>>(istream &is, vector<T> &v) {
    for (auto &e : v) is >> e;
    return is;
}
template <typename T, typename U>
inline ostream &operator<<(ostream &os, const pair<T, U> &rhs) {
    return os << rhs.first << " " << rhs.second;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
    for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
        os << *itr;
        if (++itr != end_itr) os << " ";
    }
    return os;
}

struct UnionFind {
    vector<int> par, siz;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];

        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
};
template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};
vector<vector<int>> read_tree() {
    int h, w;
    cin >> h >> w;
    if (h == 0 && w == 0) exit(0);
    vector<string> s(h + 2);
    s[0] = s[h + 1] = string(w + 2, '.');
    for (int i = 1; i <= h; i++) {
        cin >> s[i];
        s[i] = '.' + s[i] + '.';
    }
    h += 2, w += 2;
    UnionFind uf(h * w);
    rep(i, h) {
        rep(j, w) {
            if (s[i][j] == '.') {
                if (i && s[i - 1][j] == '.') uf.unite(i * w + j, (i - 1) * w + j);
                if (j && s[i][j - 1] == '.') uf.unite(i * w + j, i * w + (j - 1));
            } else {
                if (i && s[i - 1][j] == '#') uf.unite(i * w + j, (i - 1) * w + j);
                if (j && s[i][j - 1] == '#') uf.unite(i * w + j, i * w + (j - 1));
                if (i && j && s[i - 1][j - 1] == '#') uf.unite(i * w + j, (i - 1) * w + (j - 1));
                if (i && j + 1 < w && s[i - 1][j + 1] == '#') uf.unite(i * w + j, (i - 1) * w + (j + 1));
            }
        }
    }
    int C = 0;
    int n = h * w;
    vector<int> cmp(n);
    cmp[uf.find(0)] = C++;
    rep(i, n) {
        if (uf.same(0, i)) continue;
        if (uf.find(i) == i) cmp[i] = C++;
    }
    rep(i, n) cmp[i] = cmp[uf.find(i)];
    vector<vector<int>> g(C);
    rep(i, h) {
        rep(j, w) {
            if (s[i][j] == '.') {
                if (i && s[i - 1][j] == '#') {
                    g[cmp[(i - 1) * w + j]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[(i - 1) * w + j]);
                }

                if (j && s[i][j - 1] == '#') {
                    g[cmp[i * w + j - 1]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[i * w + j - 1]);
                }

                if (i + 1 < h && s[i + 1][j] == '#') {
                    g[cmp[(i + 1) * w + j]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[(i + 1) * w + j]);
                }

                if (j + 1 < w && s[i][j + 1] == '#') {
                    g[cmp[i * w + j + 1]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[i * w + j + 1]);
                }
            }
        }
    }
    rep(i, C) { compress(g[i]); }
    // rep(i, C) { cout << g[i] << endl; }
    return g;
}
using mint = modint<998244353>;
mint C = 97;
mint rooted_tree_hash(vector<vector<int>> g) {
    int n = g.size();
    vector<mint> h(n, 1);
    function<void(int, int)> dfs = [&](int v, int p) {
        for (int u : g[v]) {
            if (u == p) continue;
            dfs(u, v);
            h[v] *= (h[u]*h[u] + C);
        }
    };
    dfs(0, -1);
    return h[0];
}
void solve() {
    auto g1 = read_tree();
    auto g2 = read_tree();
    if (g1.size() != g2.size()) {
        cout << "no" << endl;
        return;
    }
    mint h1 = rooted_tree_hash(g1);
    mint h2 = rooted_tree_hash(g2);
    if (h1 == h2)
        cout << "yes" << endl;
    else
        cout << "no" << endl;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t = 1;
    // cin >> t;
    while (1) solve();
}
accuracy: 1
time_ms: 30
memory_kb: 4096
final_rank: 1

code_snippet: // C++ includes used for precompiling -*- C++ -*-
// Copyright (C) 2003-2013 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://w...content-available-to-author-only...u.org/licenses/>.
/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */
// 17.4.1.2 Headers
// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <unordered_set>

#endif
using namespace std;
using ll = long long;
using ull = unsigned long long;
using uint = unsigned int;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T &a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T &a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T>
inline void compress(vector<T> &a) {
    sort(a.begin(), a.end());
    a.erase(unique(a.begin(), a.end()), a.end());
}
template <class T>
T rand(T l, T r) {
    static mt19937 mt(random_device{}());
    // [l, r)
    if constexpr (is_integral_v<T>) {
        return uniform_int_distribution<T>(l, r - 1)(mt);
    } else if constexpr (is_floating_point_v<T>) {
        return uniform_real_distribution<T>(l, r)(mt);
    }
}
constexpr int INF = 1001001001;
constexpr ll llINF = 3000000000000000010;
struct linear_sieve {
    vector<int> least_factor, prime_list;
    linear_sieve(int n) : least_factor(n + 1, 0) {
        for (int i = 2; i <= n; i++) {
            if (least_factor[i] == 0) {
                least_factor[i] = i;
                prime_list.push_back(i);
            }
            for (int p : prime_list) {
                if (ll(i) * p > n || p > least_factor[i]) break;
                least_factor[i * p] = p;
            }
        }
    }
};
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint &operator+=(const modint &p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator-=(const modint &p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint &operator*=(const modint &p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint &operator/=(const modint &p) {
        *this *= p.inv();
        return *this;
    }
    modint operator-() const { return modint(-x); }
    modint operator+(const modint &p) const { return modint(*this) += p; }
    modint operator-(const modint &p) const { return modint(*this) -= p; }
    modint operator*(const modint &p) const { return modint(*this) *= p; }
    modint operator/(const modint &p) const { return modint(*this) /= p; }
    bool operator==(const modint &p) const { return x == p.x; }
    bool operator!=(const modint &p) const { return x != p.x; }
    modint inv() const {
        int a = x, b = modulo, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return modint(u);
    }
    modint pow(int64_t n) const {
        modint ret(1), mul(x);
        while (n > 0) {
            if (n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }
    friend ostream &operator<<(ostream &os, const modint &p) { return os << p.x; }
    friend istream &operator>>(istream &is, modint &a) {
        int64_t t;
        is >> t;
        a = modint<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
ll extgcd(ll a, ll b, ll &x, ll &y) {
    // ax+by=gcd(|a|,|b|)
    if (a < 0 || b < 0) {
        ll d = extgcd(abs(a), abs(b), x, y);
        if (a < 0) x = -x;
        if (b < 0) y = -y;
        return d;
    }
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
template <class T>
vector<T> dijkstra(vector<vector<pair<int, T>>> &g, vector<int> start) {
    using P = pair<T, int>;
    vector<T> dp(g.size(), numeric_limits<T>::max());
    priority_queue<P, vector<P>, greater<P>> que;
    for (int s : start) {
        dp[s] = 0;
        que.push({0, s});
    }
    while (que.size()) {
        auto [d, v] = que.top();
        que.pop();
        if (dp[v] != d) continue;
        for (auto [u, c] : g[v]) {
            if (chmin(dp[u], d + c)) que.push({dp[u], u});
        }
    }
    return dp;
}

vector<int> BFS01(vector<vector<pair<int, int>>> &g, vector<int> start) {
    vector<int> dp(g.size(), numeric_limits<int>::max());
    deque<int> que;
    for (int s : start) {
        dp[s] = 0;
        que.push_front(s);
    }
    while (que.size()) {
        auto v = que.front();
        que.pop_front();
        for (auto [u, c] : g[v]) {
            if (chmin(dp[u], dp[v] + c)) {
                if (c == 0)
                    que.push_front(u);
                else
                    que.push_back(u);
            }
        }
    }
    return dp;
}
template <typename T, typename U>
inline istream &operator>>(istream &is, pair<T, U> &rhs) {
    return is >> rhs.first >> rhs.second;
}
template <typename T>
inline istream &operator>>(istream &is, vector<T> &v) {
    for (auto &e : v) is >> e;
    return is;
}
template <typename T, typename U>
inline ostream &operator<<(ostream &os, const pair<T, U> &rhs) {
    return os << rhs.first << " " << rhs.second;
}
template <typename T>
inline ostream &operator<<(ostream &os, const vector<T> &v) {
    for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
        os << *itr;
        if (++itr != end_itr) os << " ";
    }
    return os;
}

struct UnionFind {
    vector<int> par, siz;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];

        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
};
template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};
vector<vector<int>> read_tree() {
    int h, w;
    cin >> h >> w;
    if (h == 0 && w == 0) exit(0);
    vector<string> s(h + 2);
    s[0] = s[h + 1] = string(w + 2, '.');
    for (int i = 1; i <= h; i++) {
        cin >> s[i];
        s[i] = '.' + s[i] + '.';
    }
    h += 2, w += 2;
    UnionFind uf(h * w);
    rep(i, h) {
        rep(j, w) {
            if (s[i][j] == '.') {
                if (i && s[i - 1][j] == '.') uf.unite(i * w + j, (i - 1) * w + j);
                if (j && s[i][j - 1] == '.') uf.unite(i * w + j, i * w + (j - 1));
            } else {
                if (i && s[i - 1][j] == '#') uf.unite(i * w + j, (i - 1) * w + j);
                if (j && s[i][j - 1] == '#') uf.unite(i * w + j, i * w + (j - 1));
                if (i && j && s[i - 1][j - 1] == '#') uf.unite(i * w + j, (i - 1) * w + (j - 1));
                if (i && j + 1 < w && s[i - 1][j + 1] == '#') uf.unite(i * w + j, (i - 1) * w + (j + 1));
            }
        }
    }
    int C = 0;
    int n = h * w;
    vector<int> cmp(n);
    cmp[uf.find(0)] = C++;
    rep(i, n) {
        if (uf.same(0, i)) continue;
        if (uf.find(i) == i) cmp[i] = C++;
    }
    rep(i, n) cmp[i] = cmp[uf.find(i)];
    vector<vector<int>> g(C);
    rep(i, h) {
        rep(j, w) {
            if (s[i][j] == '.') {
                if (i && s[i - 1][j] == '#') {
                    g[cmp[(i - 1) * w + j]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[(i - 1) * w + j]);
                }

                if (j && s[i][j - 1] == '#') {
                    g[cmp[i * w + j - 1]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[i * w + j - 1]);
                }

                if (i + 1 < h && s[i + 1][j] == '#') {
                    g[cmp[(i + 1) * w + j]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[(i + 1) * w + j]);
                }

                if (j + 1 < w && s[i][j + 1] == '#') {
                    g[cmp[i * w + j + 1]].push_back(cmp[i * w + j]);
                    g[cmp[i * w + j]].push_back(cmp[i * w + j + 1]);
                }
            }
        }
    }
    rep(i, C) { compress(g[i]); }
    // rep(i, C) { cout << g[i] << endl; }
    return g;
}
using mint = modint<998244353>;
mint C = 97;
mint rooted_tree_hash(vector<vector<int>> g) {
    int n = g.size();
    vector<mint> h(n, 1);
    function<void(int, int)> dfs = [&](int v, int p) {
        for (int u : g[v]) {
            if (u == p) continue;
            dfs(u, v);
            h[v] *= (h[u] + C);
        }
    };
    dfs(0, -1);
    return h[0];
}
void solve() {
    auto g1 = read_tree();
    auto g2 = read_tree();
    if (g1.size() != g2.size()) {
        cout << "no" << endl;
        return;
    }
    mint h1 = rooted_tree_hash(g1);
    mint h2 = rooted_tree_hash(g2);
    if (h1 == h2)
        cout << "yes" << endl;
    else
        cout << "no" << endl;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t = 1;
    // cin >> t;
    while (1) solve();
}
accuracy: 1
time_ms: 30
memory_kb: 4096
final_rank: 1

code_snippet: #ifdef LOCAL
#define _GLIBCXX_DEBUG
#pragma GCC optimize("O0")
#else
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#endif

#include <bits/stdc++.h>
// #include <bits/extc++.h>
using namespace std;

#include <atcoder/all>

// #include <atcoder/modint>
// using mint = atcoder::modint998244353;
// istream& operator>>(istream& in, mint& x) {
//     long long a;
//     in >> a;
//     x = a;
//     return in;
// }
// ostream& operator<<(ostream& out, const mint& x) {
//     return out << x.val();
// }

using ll = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using f128 = __float128;

template <class T>
constexpr T infty = 0;
template <>
constexpr int infty<int> = 1'000'000'000;
template <>
constexpr ll infty<ll> = ll(infty<int>) * infty<int> * 2;
template <>
constexpr u32 infty<u32> = infty<int>;
template <>
constexpr u64 infty<u64> = infty<ll>;
template <>
constexpr i128 infty<i128> = i128(infty<ll>) * infty<ll>;
template <>
constexpr double infty<double> = infty<ll>;
template <>
constexpr long double infty<long double> = infty<ll>;

using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
using vvi = vvc<int>;
using vvl = vvc<ll>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using vvvvvc = vector<vvvvc<T>>;
template <class T>
using pqg = std::priority_queue<T, vector<T>, greater<T>>;
template <class T, class U>
using umap = unordered_map<T, U>;

// template <typename K>
// using tree = __gnu_pbds::tree<K, __gnu_pbds::null_type, std::less<>,
//                               __gnu_pbds::rb_tree_tag,
//                               __gnu_pbds::tree_order_statistics_node_update>;

#define vv(type, name, h, ...) \
    vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...)     \
    vector<vector<vector<type>>> name( \
        h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)         \
    vector<vector<vector<vector<type>>>> name( \
        a, vector<vector<vector<type>>>(       \
               b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))

// FOR(a) :=  for (ll _ = 0; _ < (ll)a; ++_)
// FOR(i, a) := for (ll i = 0; i < (ll)a; ++i)
// FOR(i, a, b) := for (ll i = a; i < (ll)b; ++i)
// FOR(i, a, b, c) := for (ll i = a; i < (ll)b; i += (c))
// FOR_R(a) := for (ll i = (a) - 1; i >= 0; --i)
// FOR_R(i, a) := for (ll i = (a) - 1; i >= 0; --i)
// FOR_R(i, a, b) := for (ll i = (b) - 1; i >= (ll)a; --i)
#define FOR1(a) for (ll _ = 0; _ < (ll)a; ++_)
#define FOR2(i, a) for (ll i = 0; i < (ll)a; ++i)
#define FOR3(i, a, b) for (ll i = a; i < (ll)b; ++i)
#define FOR4(i, a, b, c) for (ll i = a; i < (ll)b; i += (c))
#define FOR1_R(a) for (ll i = (a) - 1; i >= 0; --i)
#define FOR2_R(i, a) for (ll i = (a) - 1; i >= 0; --i)
#define FOR3_R(i, a, b) for (ll i = (b) - 1; i >= (ll)a; --i)
#define overload4(a, b, c, d, e, ...) e
#define overload3(a, b, c, d, ...) d
#define FOR(...) overload4(__VA_ARGS__, FOR4, FOR3, FOR2, FOR1)(__VA_ARGS__)
#define FOR_R(...) overload3(__VA_ARGS__, FOR3_R, FOR2_R, FOR1_R)(__VA_ARGS__)

#define FOR_subset(t, s) \
    for (int t = (s); t >= 0; t = (t == 0 ? -1 : (t - 1) & (s)))
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()

int popcnt(int x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(ll x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }
int popcnt_mod_2(int x) { return __builtin_parity(x); }
int popcnt_mod_2(u32 x) { return __builtin_parity(x); }
int popcnt_mod_2(ll x) { return __builtin_parityll(x); }
int popcnt_mod_2(u64 x) { return __builtin_parityll(x); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 1, 2)
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(u32 x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int topbit(u64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 0, 2)
int lowbit(int x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(u32 x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int lowbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
int lowbit(u64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }

template <typename T>
T floor(T a, T b) {
    return a / b - (a % b && (a ^ b) < 0);
}
template <typename T>
T ceil(T x, T y) {
    return floor(x + y - 1, y);
}
template <typename T>
T bmod(T x, T y) {
    return x - y * floor(x, y);
}
template <typename T>
pair<T, T> divmod(T x, T y) {
    T q = floor(x, y);
    return {q, x - q * y};
}

template <typename T, typename U>
T POW(U x_, int n) {
    T x = x_;
    T ret = 1;
    while (n > 0) {
        if (n & 1) ret *= x;
        x *= x;
        n >>= 1;
    }
    return ret;
}

template <typename T, typename U>
T SUM(const vector<U> &A) {
    T sm = 0;
    for (auto &&a : A) sm += a;
    return sm;
}

#define LB(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define UB(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define UNIQUE(x) \
    sort(all(x)), x.erase(unique(all(x)), x.end()), x.shrink_to_fit()

template <class T, class S>
inline bool chmax(T &a, const S &b) {
    return (a < b ? a = b, 1 : 0);
}
template <class T, class S>
inline bool chmin(T &a, const S &b) {
    return (a > b ? a = b, 1 : 0);
}

// ? は -1
vc<int> s_to_vi(const string &S, char first_char) {
    vc<int> A(S.size());
    FOR(i, S.size()) { A[i] = (S[i] != '?' ? S[i] - first_char : -1); }
    return A;
}

template <typename T, typename U>
vector<T> cumsum(vector<U> &A, int off = 1) {
    int N = A.size();
    vector<T> B(N + 1);
    FOR(i, N) { B[i + 1] = B[i] + A[i]; }
    if (off == 0) B.erase(B.begin());
    return B;
}

template <typename T>
vector<int> argsort(const vector<T> &A) {
    vector<int> ids(A.size());
    iota(all(ids), 0);
    sort(all(ids),
         [&](int i, int j) { return (A[i] == A[j] ? i < j : A[i] < A[j]); });
    return ids;
}

// A[I[0]], A[I[1]], ...
template <typename T>
vc<T> rearrange(const vc<T> &A, const vc<int> &I) {
    vc<T> B(I.size());
    FOR(i, I.size()) B[i] = A[I[i]];
    return B;
}

template<class... T>
constexpr auto min(T... a){
    return min(initializer_list<common_type_t<T...>>{a...});
}
template<class... T>
constexpr auto max(T... a){
    return max(initializer_list<common_type_t<T...>>{a...});
}

void print(){
    cout << '\n';
}
template<class T>
void print(const T& a){
    cout << a << '\n';
}
template<class T, class... Ts>
void print(const T& a, const Ts&... b){
    cout << a;
    (cout << ... << (cout << ' ', b));
    cout << '\n';
}
template<class T>
void print(vector<T> &a){
    for (int i = 0; i < (int)a.size(); ++i) {
        cout << a[i] << " \n"[i == (int)a.size() - 1];
    }
}
template<class T>
void print(vector<T> &&a){
    for (int i = 0; i < (int)a.size(); ++i) {
        cout << a[i] << " \n"[i == (int)a.size() - 1];
    }
}
template<class T>
void print(vector<vector<T>> &a){
    for (int i = 0; i < (int)a.size(); ++i) {
        for (int j = 0; j < (int)a[i].size(); ++j) {
            cout << a[i][j] << " \n"[j == (int)a[i].size() - 1];
        }
    }
}
template<class T>
void print(vector<vector<T>> &&a){
    for (int i = 0; i < (int)a.size(); ++i) {
        for (int j = 0; j < (int)a[i].size(); ++j) {
            cout << a[i][j] << " \n"[j == (int)a[i].size() - 1];
        }
    }
}
void YESNO(bool b) { cout << (b ? "YES" : "NO") << endl; }
void YesNo(bool b) { cout << (b ? "Yes" : "No") << endl; }

#ifdef LOCAL
// https://zenn.dev/sassan/articles/19db660e4da0a4
#include "/Library/cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
// CPP_DUMP_DEFINE_EXPORT_OBJECT(mint, val());
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif


//----------------------------------------------------------------

string stroftree() {
    ll h, w;
    cin >> h >> w;
    if (h == 0 && w == 0) exit(0);
    h += 2;
    w += 2;
    vc<string> p(h);
    p[0] = string(w, '.');
    FOR(i, 1, h - 1) {
        string s;
        cin >> s;
        p[i] = '.' + s + '.';
    }
    p[h-1] = string(w, '.');
    atcoder::dsu uf(h * w);
    FOR(i, h) FOR(j, w - 1) {
        ll idx = i * w + j;
        if (p[i][j] == p[i][j+1]) {
            uf.merge(idx, idx + 1);
        }
    }
    FOR(i, h - 1) FOR(j, w) {
        ll idx = i * w + j;
        if (p[i][j] == p[i+1][j]) {
            uf.merge(idx, idx + w);
        }
    }
    FOR(i, h - 1) FOR(j, 1, w) {
        ll a = i * w + j;
        ll b = (i + 1) * w + j - 1;
        if (p[i][j] == '#' && p[i+1][j-1] == '#') {
            uf.merge(a, b);
        }
    }
    FOR(i, h - 1) FOR(j, w - 1) {
        ll a = i * w + j;
        ll b = (i + 1) * w + j + 1;
        if (p[i][j] == '#' && p[i+1][j+1] == '#') {
            uf.merge(a, b);
        }
    }
    vv(ll, lbl, h, w);
    auto groups = uf.groups();
    FOR(gpi, groups.size()) {
        FOR(pti, groups[gpi].size()) {
            ll idx = groups[gpi][pti];
            ll i = idx / w;
            ll j = idx % w;
            lbl[i][j] = gpi;
        }
    }
    // dump(lbl);
    ll n = groups.size();
    ll di[] = {0, 0, 1, -1};
    ll dj[] = {1, -1, 0, 0};
    vc<set<ll>> vs(n);
    FOR(i, h) FOR(j, w) {
        FOR(k, 4) {
            ll ni = i + di[k];
            ll nj = j + dj[k];
            if (ni < 0 || ni >= h || nj < 0 || nj >= w) {
                continue;
            }
            if (lbl[i][j] == lbl[ni][nj]) continue;
            vs[lbl[i][j]].emplace(lbl[ni][nj]);
        }
    }
    ll slbl = lbl[0][0];
    vc<bool> used(n);
    vvl G(n);
    queue<ll> que;
    que.emplace(slbl);
    while (!que.empty()) {
        ll frm = que.front();
        que.pop();
        used[frm] = true;
        for (auto x : vs[frm]) {
            if (used[x]) continue;
            G[frm].emplace_back(x);
            que.emplace(x);
        }
    }
    auto dfs = [&](auto&& self, ll v) -> string {
        vc<string> ss(G[v].size());
        FOR(i, G[v].size()) {
            ss[i] = '(' + self(self, G[v][i]) + ')';
        }
        sort(all(ss));
        string ret = "";
        FOR(i, ss.size()) {
            ret += ss[i];
        }
        return ret;
    };
    return dfs(dfs, slbl);
}

void solve() {
    string s = stroftree();
    string t = stroftree();
    dump(s, t);
    if (s == t) {
        print("yes");
    } else {
        print("no");
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(20);
    CPP_DUMP_SET_OPTION(max_line_width, 80);
    CPP_DUMP_SET_OPTION(log_label_func, cpp_dump::log_label::filename());
    CPP_DUMP_SET_OPTION(enable_asterisk, true);
    while (true) {
        solve();
    }
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 4196
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#include <unordered_map>
#include <stdlib.h>
using namespace std;
#define rep(i, a, n) for(ll i = a; i < n; i++)
#define rrep(i, a, n) for(ll i = a; i >= n; i--)
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define all(x) (x).begin(), (x).end()
//constexpr ll MOD = 1000000007;
constexpr ll MOD = 998244353;
constexpr int IINF = 1001001001;
constexpr ll INF = 1LL<<60;
template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}

ll gcd(ll a, ll b){
    if(a%b == 0){
      return b;
    }else{
      return gcd(b, a%b);
    }
}

ll lcm(ll a, ll b){
    return a*b / gcd(a, b);
}

ll powMod(ll x, ll n) {
    if (n == 0) return 1 % MOD;
    ll val = powMod(x, n / 2);
    val *= val;
    val %= MOD;
    if (n % 2 == 1) val *= x;
    return val % MOD;
}

class UnionFind {
    vector<ll> parent, maxi, mini;
    inline ll root(ll n){
        return (parent[n] < 0? n:parent[n] = root(parent[n]));
    }
public:
    UnionFind(ll n_ = 1): parent(n_, -1), maxi(n_), mini(n_){
        iota(maxi.begin(), maxi.end(), 0);
        iota(mini.begin(), mini.end(), 0);
    }

    inline bool same(ll x, ll y){
        return root(x) == root(y);
    }

    inline void unite(ll x, ll y){
        ll rx = root(x);
        ll ry = root(y);
        if(rx == ry) return;
        if(parent[rx] > parent[ry]) swap(rx, ry);
        parent[rx] += parent[ry];
        parent[ry] = rx;
        maxi[rx] = std::max(maxi[rx],maxi[ry]);
        mini[rx] = std::min(mini[rx],mini[ry]);
    }

    inline ll min(ll x){
        return mini[root(x)];
    }

    inline ll max(ll x){
        return maxi[root(x)];
    }

    inline ll size(ll x){
        return (-parent[root(x)]);
    }

    inline ll operator[](ll x){
        return root(x);
    }

    map<ll,vector<ll>> groups(){
        map<ll,vector<ll>> mp;
        rep(i,0,parent.size())mp[root(i)].push_back(i);
        return mp;
    }
};

string solve(vector<string> p){
    ll h = p.size();
    ll w = p[0].size();
    UnionFind uf(h*w);
    rep(i,0,h)rep(j,0,w){
        if(i < h-1 && p[i][j] == p[i+1][j]) uf.unite(i*w+j, (i+1)*w+j);
        if(j < w-1 && p[i][j] == p[i][j+1]) uf.unite(i*w+j, i*w+j+1);
        if(i < h-1 && j < w-1 && p[i][j] == p[i+1][j+1] && p[i][j] == '#') uf.unite(i*w+j, (i+1)*w+j+1);
        if(i > 0 && j < w-1 && p[i][j] == p[i-1][j+1] && p[i][j] == '#') uf.unite(i*w+j, (i-1)*w+j+1);
    }
    auto tmp = uf.groups();
    map<ll,set<ll>> g;
    rep(i,0,h)rep(j,0,w){
        if(i < h-1 && p[i][j] != p[i+1][j]){
            g[uf[i*w+j]].insert(uf[(i+1)*w+j]);
            g[uf[(i+1)*w+j]].insert(uf[i*w+j]);
        }
        if(j < w-1 && p[i][j] != p[i][j+1]){
            g[uf[i*w+j]].insert(uf[i*w+j+1]);
            g[uf[i*w+j+1]].insert(uf[i*w+j]);
        }
    }
    vector<ll> check(h*w,0);
    auto dfs = [&](auto dfs, ll v, ll par) -> string {
        // cout << v << " " << par << endl;
        check[v] = 1;
        string res = "(";
        vector<string> vec;
        for(auto nv: g[v]){
            if(check[nv]) continue;
            string x = dfs(dfs, nv, v);
            vec.push_back(x);
        }
        sort(all(vec));
        for(auto x: vec) res += x;
        res.push_back(')');
        return res;
    };
    return dfs(dfs, uf[0], -1);    
}

string solve_(vector<string> p){
    ll h = p.size(), w = p[0].size();
    vector<string> np(h+2, string(w+2, '.'));
    rep(i,0,h)rep(j,0,w) np[i+1][j+1] = p[i][j];
    return solve(np);
}

int main() {
    while(true){
        ll h1, w1; cin >> h1 >> w1;
        if(h1*w1 == 0) break;
        vector<string> p1(h1);
        rep(i,0,h1) cin >> p1[i];
        string s1 = solve_(p1);
        ll h2, w2; cin >> h2 >> w2;
        vector<string> p2(h2);
        rep(i,0,h2) cin >> p2[i];
        string s2 = solve_(p2);
        if(s1 == s2) cout << "yes" << endl;
        else cout << "no" << endl;
        // cout << s1 << endl << s2 << endl << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 4296
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace std;

namespace noya2 {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
    os << p.first << " " << p.second;
    return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    int s = (int)v.size();
    for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
    return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (auto &x : v) is >> x;
    return is;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
    cin >> t;
    in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
    cout << t;
    if (sizeof...(u)) cout << sep;
    out(u...);
}

template<typename T>
void out(const vector<vector<T>> &vv){
    int s = (int)vv.size();
    for (int i = 0; i < s; i++) out(vv[i]);
}

struct IoSetup {
    IoSetup(){
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(7);
    }
} iosetup_noya2;

const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 =  998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }


unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
    if (a == 0 || b == 0) return a + b;
    int n = __builtin_ctzll(a); a >>= n;
    int m = __builtin_ctzll(b); b >>= m;
    while (a != b) {
        int mm = __builtin_ctzll(a - b);
        bool f = a > b;
        unsigned long long c = f ? a : b;
        b = f ? b : a;
        a = (c - b) >> mm;
    }
    return a << min(n, m);
}

template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }

long long sqrt_fast(long long n) {
    if (n <= 0) return 0;
    long long x = sqrt(n);
    while ((x + 1) * (x + 1) <= n) x++;
    while (x * x > n) x--;
    return x;
}

template<typename T> T floor_div(const T n, const T d) {
    assert(d != 0);
    return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}

template<typename T> T ceil_div(const T n, const T d) {
    assert(d != 0);
    return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}

template<typename T> void uniq(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}

template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }

template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }

} // namespace noya2

#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()

using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;

namespace noya2{

/*　~ (. _________ . /)　*/

}

using namespace noya2;


#include <cassert>
#include <concepts>

template <int m>
struct static_modint {
    using mint = static_modint;
  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }
    constexpr static_modint() : _v(0) {}
    template<std::signed_integral T>
    constexpr static_modint(T v){
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template<std::unsigned_integral T>
    constexpr static_modint(T v){
        _v = (unsigned int)(v % umod());
    }
    constexpr unsigned int val() const { return _v; }
    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }
    constexpr mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    constexpr mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    constexpr mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    constexpr mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }
    constexpr mint operator+() const { return *this; }
    constexpr mint operator-() const { return mint() - *this; }
    constexpr mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    constexpr mint inv() const {
        assert(_v);
        return pow(umod() - 2);
    }
    friend constexpr mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend constexpr mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend constexpr mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend constexpr mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend constexpr bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend constexpr bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }
    friend std::ostream &operator<<(std::ostream &os, const mint& p) {
        return os << p.val();
    }
    friend std::istream &operator>>(std::istream &is, mint &a) {
        long long t; is >> t;
        a = mint(t);
        return (is);
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
};

using mint = static_modint<998244353>;

vector<mint> wdep;

void init(){
    wdep.resize(1001001);
    mt19937_64 mt(-1);
    rep(i,wdep.size()){
        wdep[i] = mt();
    }
}

ull calc_hash(int h, int w){
    vector<string> a(h+4,string(w+4,'?'));
    rep(i,h){
        string s; in(s);
        rep(j,w){
            a[i+2][j+2] = s[j];
        }
    }
    vector done(h+4,vector<bool>(w+4,false));
    auto findcc = [&](int sx, int sy){
        int kk = (a[sx][sy] == '.' ? 4 : 8);
        vector<pii> ret;
        queue<pii> que;
        que.emplace(sx,sy);
        done[sx][sy] = true;
        while (!que.empty()){
            auto [x, y] = que.front(); que.pop();
            ret.emplace_back(x,y);
            rep(k,kk){
                int nx = x + dx[k];
                int ny = y + dy[k];
                if (!done[nx][ny] && a[sx][sy] == a[nx][ny]){
                    done[nx][ny] = true;
                    que.emplace(nx,ny);
                }
            }
        }
        return ret;
    };
    auto dfs = [&](auto sfs, vector<pii> cc) -> pair<mint,int> {
        // out(cc);
        int hei = 0;
        mint prd = 1;
        for (auto [ix, iy] : cc){
            rep(k,4){
                int nx = ix + dx[k];
                int ny = iy + dy[k];
                if (!(range(0,nx,h+4) && range(0,ny,w+4))) continue;
                if (done[nx][ny]) continue;
                auto ncc = findcc(nx,ny);
                auto [dp, he] = sfs(sfs,ncc);
                chmax(hei,he+1);
                prd *= dp;
            }
        }
        return {prd+wdep[hei],hei};
    };
    vector<pii> cc;
    rep(i,h+4) rep(j,w+4){
        if (i == 0 || i == h+3 || j == 0 || j == w+3){
            a[i][j] = '#';
            done[i][j] = true;
            cc.emplace_back(i,j);
        }
        else if (i == 1 || i == h+2 || j == 1 || j == w+2){
            a[i][j] = '.';
        }
    }
    // rep(i,h+4) out(a[i]);
    return dfs(dfs,cc).first.val();
}

void solve(int h1, int w1){
    ull x1 = calc_hash(h1,w1);
    int h2, w2; in(h2,w2);
    ull x2 = calc_hash(h2,w2);
    out(x1 == x2 ? "yes" : "no");
}

int main(){
    init();
    while (true){
        int h, w; in(h,w);
        if (h == 0) break;
        solve(h,w);
    }
}
accuracy: 1
time_ms: 40
memory_kb: 7464
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;


class UnionFind
  {
  private:
      vector<ll> p;
      vector<ll> rank;
  public:
      UnionFind(ll n){
          p.resize(n,-1);
          rank.resize(n,1);
      }
      ll find(ll x){
          if(p[x]<0)return x;
          return p[x]=find(p[x]);
      }
      void unite(ll x,ll y){
          x = find(x);
          y = find(y);
      if(x == y)return;
          if(rank[x] > rank[y])swap(x,y);
          if(rank[x] == rank[y])rank[y]++;
          p[y] += p[x];
          p[x] = y;
      }
      ll size(ll x){
          return -p[find(x)];
      }
      bool same(ll x, ll y){
          return find(x) == find(y);
      }
  };
 
vector<int> dx = {1,0,-1,0,1,1,-1,-1};
vector<int> dy = {0,1,0,-1,1,-1,1,-1};

const ll mod = 998244353;
const ll X = 19960515;

int main(){
	auto f = [&](int H , int W , vector<vector<int>> G)->ll{
		UnionFind uf(H*W);
		for(int i = 0; i < H; i++){
			for(int j = 0; j < W; j++){
				for(int k = 0; k < (G[i][j] == 1 ? 8:4); k++){
					int ni = i + dx[k];
					int nj = j + dy[k];
					if(ni < 0 || ni >= H)continue;
					if(nj < 0 || nj >= W)continue;
					if(G[i][j] != G[ni][nj])continue;
					uf.unite(i*W+j , ni*W+nj);
				}
			}
		}
		int N = 0;
		vector<int> idx(H*W,-1);
		for(int i = 0; i < H*W; i++)if(uf.find(i) == i){
			idx[i] = N;
			N++;
		}
		vector<set<int>> graph(N);
		for(int i = 0; i < H; i++){
			for(int j = 0; j < W; j++){
				for(int k = 0; k < 4; k++){
					int ni = i + dx[k];
					int nj = j + dy[k];
					if(ni < 0 || ni >= H)continue;
					if(nj < 0 || nj >= W)continue;
					int x = uf.find(i*W+j);
					x = idx[x];
					int y = uf.find(ni*W+nj);
					y = idx[y];
					if(x == y)continue;
					graph[x].insert(y);
					graph[y].insert(x);
				}
			}
		}
		int root = idx[uf.find(0)];
		auto dfs = [&](auto dfs , int v , int p = -1)->ll{
			ll ret = 1;
			for(auto c:graph[v]){
				if(c == p)continue;
				ret *= (X + dfs(dfs , c , v));
				ret %= mod;
			}
			return ret;
		};
		return dfs(dfs, root);
	};
	while(1){
		int H1,W1; cin >> H1 >> W1;
		if(H1 == 0){
			return 0;
		}
		vector<vector<int>> G1(H1+2 , vector<int>(W1+2));
		for(int i = 1; i <= H1; i++){
			for(int j = 1; j <= W1; j++){
				char c; cin >> c;
				if(c == '#')G1[i][j] = 1;
			}
		}
		int H2,W2; cin >> H2 >> W2;
		vector<vector<int>> G2(H2+2 , vector<int>(W2+2));
		for(int i = 1; i <= H2; i++){
			for(int j = 1; j <= W2; j++){
				char c; cin >> c;
				if(c == '#')G2[i][j] = 1;
			}
		}
		H1 += 2;
		W1 += 2;
		H2 += 2;
		W2 += 2;
		if(f(H1,W1,G1) == f(H2,W2,G2))cout << "yes" << endl;
		else cout << "no" << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 4096
final_rank: 14

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

int dx1[4] = {1,0,-1,0}, dy1[4] = {0,1,0,-1};
int dx2[8] = {1,1,1,0,-1,-1,-1,0}, dy2[8] = {-1,0,1,1,1,0,-1,-1};

map<vector<int>,int> mp;

vector<vector<int>> MakeGraph(int N, int M) {
    N += 2, M += 2;
    vector<vector<char>> C(N,vector<char>(M,'.'));
    rep(i,1,N-1) rep(j,1,M-1) cin >> C[i][j];
    int Cur = 0;
    vector<vector<int>> B(N, vector<int>(M,-1));
    rep(i,0,N) {
        rep(j,0,M) {
            if (B[i][j] == -1 && C[i][j] == '.') {
                queue<pair<int,int>> Q;
                Q.push({i,j});
                B[i][j] = Cur;
                while(!Q.empty()) {
                    auto [X,Y] = Q.front();
                    Q.pop();
                    rep(k,0,4) {
                        int NX = X + dx1[k], NY = Y + dy1[k];
                        if (0 <= NX && NX < N && 0 <= NY && NY < M) {
                            if (C[NX][NY] == '.' && B[NX][NY] == -1) {
                                B[NX][NY] = Cur;
                                Q.push({NX,NY});
                            }
                        }
                    }
                }
                Cur++;
            }
        }
    }
    rep(i,0,N) {
        rep(j,0,M) {
            if (B[i][j] == -1 && C[i][j] == '#') {
                queue<pair<int,int>> Q;
                Q.push({i,j});
                B[i][j] = Cur;
                while(!Q.empty()) {
                    auto [X,Y] = Q.front();
                    Q.pop();
                    rep(k,0,8) {
                        int NX = X + dx2[k], NY = Y + dy2[k];
                        if (0 <= NX && NX < N && 0 <= NY && NY < M) {
                            if (C[NX][NY] == '#' && B[NX][NY] == -1) {
                                B[NX][NY] = Cur;
                                Q.push({NX,NY});
                            }
                        }
                    }
                }
                Cur++;
            }
        }
    }
    vector<vector<pair<int,int>>> P(Cur);
    rep(i,0,N) {
        rep(j,0,M) {
            P[B[i][j]].push_back({i,j});
        }
    }
    vector<vector<int>> Ret(Cur);
    vector<bool> used(N,false);
    queue<int> Q2;
    Q2.push(0);
    used[0] = true;
    while(!Q2.empty()) {
        int Z = Q2.front();
        Q2.pop();
        for (auto [X,Y] : P[Z]) {
            rep(i,0,4) {
                int NX = X + dx1[i], NY = Y + dy1[i];
                if (0 <= NX && NX < N && 0 <= NY && NY < M) {
                    if (!used[B[NX][NY]]) {
                        Ret[Z].push_back(B[NX][NY]);
                        used[B[NX][NY]] = true;
                        Q2.push(B[NX][NY]);
                    }
                }
            }
        }
    }
    return Ret;
}

int ID = 0;

int DFS(vector<vector<int>>& V, int X) {
    vector<int> A;
    for (int NX : V[X]) {
        A.push_back(DFS(V,NX));
    }
    sort(ALL(A));
    if (mp.count(A)) return mp[A];
    else {
        mp[A] = ID;
        return ID++;
    }
}

bool Compare(vector<vector<int>>& V1, vector<vector<int>>& V2) {
    if (V1.size() != V2.size()) return false;
    return DFS(V1,0) == DFS(V2,0);
}

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0 && M == 0) return 0;
    vector<vector<int>> V1 = MakeGraph(N,M);
    cin >> N >> M;
    vector<vector<int>> V2 = MakeGraph(N,M);
    cout << (Compare(V1,V2) ? "yes" : "no") << endl;
}
}
accuracy: 1
time_ms: 50
memory_kb: 3792
final_rank: 5

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

int dx1[4] = {1,0,-1,0}, dy1[4] = {0,1,0,-1};
int dx2[8] = {1,1,1,0,-1,-1,-1,0}, dy2[8] = {-1,0,1,1,1,0,-1,-1};

map<vector<int>,int> mp;

vector<vector<int>> MakeGraph(int N, int M) {
    N += 2, M += 2;
    vector<vector<char>> C(N,vector<char>(M,'.'));
    rep(i,1,N-1) rep(j,1,M-1) cin >> C[i][j];
    int Cur = 0;
    vector<vector<int>> B(N, vector<int>(M,-1));
    rep(i,0,N) {
        rep(j,0,M) {
            if (B[i][j] == -1 && C[i][j] == '.') {
                queue<pair<int,int>> Q;
                Q.push({i,j});
                B[i][j] = Cur;
                while(!Q.empty()) {
                    auto [X,Y] = Q.front();
                    Q.pop();
                    rep(k,0,4) {
                        int NX = X + dx1[k], NY = Y + dy1[k];
                        if (0 <= NX && NX < N && 0 <= NY && NY < M) {
                            if (C[NX][NY] == '.' && B[NX][NY] == -1) {
                                B[NX][NY] = Cur;
                                Q.push({NX,NY});
                            }
                        }
                    }
                }
                Cur++;
            }
        }
    }
    rep(i,0,N) {
        rep(j,0,M) {
            if (B[i][j] == -1 && C[i][j] == '#') {
                queue<pair<int,int>> Q;
                Q.push({i,j});
                B[i][j] = Cur;
                while(!Q.empty()) {
                    auto [X,Y] = Q.front();
                    Q.pop();
                    rep(k,0,8) {
                        int NX = X + dx2[k], NY = Y + dy2[k];
                        if (0 <= NX && NX < N && 0 <= NY && NY < M) {
                            if (C[NX][NY] == '#' && B[NX][NY] == -1) {
                                B[NX][NY] = Cur;
                                Q.push({NX,NY});
                            }
                        }
                    }
                }
                Cur++;
            }
        }
    }
    vector<vector<pair<int,int>>> P(Cur);
    rep(i,0,N) {
        rep(j,0,M) {
            P[B[i][j]].push_back({i,j});
        }
    }
    vector<vector<int>> Ret(Cur);
    vector<bool> used(N,false);
    queue<int> Q2;
    Q2.push(0);
    used[0] = true;
    while(!Q2.empty()) {
        int Z = Q2.front();
        Q2.pop();
        for (auto [X,Y] : P[Z]) {
            rep(i,0,4) {
                int NX = X + dx1[i], NY = Y + dy1[i];
                if (0 <= NX && NX < N && 0 <= NY && NY < M) {
                    if (!used[B[NX][NY]]) {
                        Ret[Z].push_back(B[NX][NY]);
                        used[B[NX][NY]] = true;
                        Q2.push(B[NX][NY]);
                    }
                }
            }
        }
    }
    return Ret;
}

int ID = 0;

int DFS(vector<vector<int>> V, int X) {
    vector<int> A;
    for (int NX : V[X]) {
        A.push_back(DFS(V,NX));
    }
    sort(ALL(A));
    if (mp.count(A)) return mp[A];
    else {
        mp[A] = ID;
        return ID++;
    }
}

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0 && M == 0) return 0;
    vector<vector<int>> V1 = MakeGraph(N,M);
    cin >> N >> M;
    vector<vector<int>> V2 = MakeGraph(N,M);
    cout << (DFS(V1,0) == DFS(V2,0) ? "yes" : "no") << endl;
}
}
accuracy: 1
time_ms: 70
memory_kb: 3956
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
const vector<pair<int,int>>white={{1,0},{-1,0},{0,1},{0,-1}};
const vector<pair<int,int>>black={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
vector<vector<int>>make_tree(const vector<vector<char>>&g)
{
    int h=g.size(),w=g[0].size();
    int cnt=0;
    vector<vector<bool>>vis(h,vector<bool>(w,false));
    vector<vector<int>>idx(h,vector<int>(w));
    vector<vector<pair<int,int>>>inv;
    for(int i=0;i<h;i++)for(int j=0;j<w;j++)if(!vis[i][j])
    {
        inv.push_back({});
        vis[i][j]=true;
        queue<pair<int,int>>q;
        q.push(make_pair(i,j));
        while(!q.empty())
        {
            auto[r,c]=q.front();
            q.pop();
            idx[r][c]=cnt;
            inv[cnt].push_back(make_pair(r,c));
            for(auto[dr,dc]:(g[r][c]=='.'?white:black))
            {
                int tr=r+dr,tc=c+dc;
                if(0<=tr&&tr<h&&0<=tc&&tc<w&&!vis[tr][tc]&&g[tr][tc]==g[r][c])
                {
                    vis[tr][tc]=true;
                    q.push(make_pair(tr,tc));
                }
            }
        }
        cnt++;
    }
    vector<bool>checked(cnt,false);
    checked[0]=true;
    vector<vector<int>>res(cnt);
    for(int i=0;i<cnt;i++)
    {
        // for(int j=0;j<cnt;j++)cout<<checked[j];cout<<endl;
        assert(checked[i]);
        for(auto[r,c]:inv[i])for(auto[dr,dc]:white)
        {
            int tr=r+dr,tc=c+dc;
            if(0<=tr&&tr<h&&0<=tc&&tc<w&&!checked[idx[tr][tc]])
            {
                checked[idx[tr][tc]]=true;
                res[i].push_back(idx[tr][tc]);
            }
        }
        sort(res[i].begin(),res[i].end());
        res[i].erase(unique(res[i].begin(),res[i].end()),res[i].end());
    }
    return res;
}
string tree_hash(const vector<vector<int>>&t)
{
    auto dfs=[&](auto dfs, int u, int p)->string
    {
        vector<string>cld;
        for(int v:t[u])if(v!=p)cld.push_back(dfs(dfs,v,u));
        sort(cld.begin(),cld.end());
        string res="(";
        for(auto s:cld)res+=s;
        return res+")";
    };
    return dfs(dfs,0,-1);
}
bool solve()
{
    int H1,W1;
    cin>>H1>>W1;
    if(H1==0&&W1==0)return false;
    vector<vector<char>>grid1(H1+2,vector<char>(W1+2,'.'));
    for(int i=1;i<=H1;i++)for(int j=1;j<=W1;j++)cin>>grid1[i][j];
    int H2,W2;
    cin>>H2>>W2;
    vector<vector<char>>grid2(H2+2,vector<char>(W2+2,'.'));
    for(int i=1;i<=H2;i++)for(int j=1;j<=W2;j++)cin>>grid2[i][j];
    auto T1=make_tree(grid1);
    auto T2=make_tree(grid2);
    cout<<(tree_hash(T1)==tree_hash(T2)?"yes":"no")<<endl;
    return true;
}
int main(){while(solve()){}}
accuracy: 1
time_ms: 60
memory_kb: 3760
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

bool is_end = false;

const vector<pair<int, int>> move_white = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
const vector<pair<int, int>> move_black = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

struct grid {
  // grid() : grid(0, 0, 0) {}
  // grid(int h, int w, int c) : H(h), W(w), cnt_component(c) {}
  int H, W;
  int cnt_component = 0;
  vector<vector<char>> p;
  vector<vector<int>> component_id;
  vector<vector<pair<int, int>>> component;
  // グリッドの内部のマスか判定する
  bool _within_area(int r, int c) {
    return (0 <= r && r < H && 0 <= c && c < W);
  }
  // 始点と id を指定　同じ連結成分に id を伝播する
  void _bfs_allocate_id(int r_s, int c_s, int id_s) {
    queue<pair<int, int>> que;
    const vector<pair<int, int>> dir = (p[r_s][c_s] == '.' ? move_white : move_black);
    component_id[r_s][c_s] = id_s;
    component.push_back(vector<pair<int, int>>());
    que.push(make_pair(r_s, c_s));
    while(!que.empty()) {
      auto [r, c] = que.front();
      que.pop();
      for(const auto &[dr, dc] : dir) {
        const int nr = r + dr;
        const int nc = c + dc;
        if(_within_area(nr, nc) && p[nr][nc] == p[r][c] && component_id[nr][nc] == -1) {
          component_id[nr][nc] = component_id[r][c];
          que.push(make_pair(nr, nc));
        }
      }
    }
  }
  // 全体に連結成分の id を割り振る
  void allocate_id() {
    for(int i = 0; i < H; i++) {
      for(int j = 0; j < W; j++) {
        if(component_id[i][j] != -1) continue;
        _bfs_allocate_id(i, j, cnt_component++);
      }
    }
    for(int i = 0; i < H; i++) {
      for(int j = 0; j < W; j++) {
        component[component_id[i][j]].push_back(make_pair(i, j));
      }
    }
  }
  // 木に変形する 直属の子のリストを返す
  vector<vector<int>> to_tree() {
    vector<bool> used(cnt_component);
    vector<vector<int>> child(cnt_component);
    queue<int> que;
    que.push(0);
    used[0] = true;
    while(!que.empty()) {
      const int i = que.front();
      que.pop();
      for(const auto &[r, c] : component[i]) {
        const vector<pair<int, int>> dir = (p[r][c] == '.' ? move_white : move_black);
        for(const auto &[dr, dc] : dir) {
          const int nr = r + dr;
          const int nc = c + dc;
          if(_within_area(nr, nc) && !used[component_id[nr][nc]]) {
            const int j = component_id[nr][nc];
            child[i].push_back(j);
            que.push(j);
            used[j] = true;
          }
        }
      }
    }
    return child;
  }
  // 入力を読む
  grid(int c) : cnt_component(c) {
    cin >> H >> W;
    if(H == 0 && W == 0) {
      is_end = true;
    }
    H += 2, W += 2;
    p = vector(H, vector<char>(W, '.'));
    component_id = vector(H, vector<int>(W, -1));
    for(int i = 1; i < H - 1; i++) {
      string str_in;
      cin >> str_in;
      for(int j = 1; j < W - 1; j++) {
        p[i][j] = str_in[j - 1];
      }
    }
    allocate_id();
  }
};

string hash_tree(vector<vector<int>> &child, int cur = 0) {
  if(child[cur].empty()) return "";
  vector<string> hash_child;
  for(const int &nxt : child[cur]) {
    hash_child.push_back('(' + hash_tree(child, nxt) + ')');
  }
  sort(hash_child.begin(), hash_child.end());
  string ret = "";
  for(const string &str : hash_child) {
    ret += str;
  }
  return ret;
}

bool solve() {
  grid G1(0);
  if(is_end) { return false; }
  grid G2(0);
  if(G1.cnt_component != G2.cnt_component) { cout << "no" << endl; return true; }
  vector<vector<int>> T1 = G1.to_tree();
  vector<vector<int>> T2 = G2.to_tree();
  cout << (hash_tree(T1) == hash_tree(T2) ? "yes" : "no") << endl;
  return true;
}

int main() {
  while(solve()) {}
}
accuracy: 1
time_ms: 60
memory_kb: 3928
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
#define rep(i,n) for(ll i=0;i<n;i++)

vll dx={1,0,-1,0,1,-1,1,-1};
vll dy={0,1,0,-1,1,1,-1,-1};
vector<vll> to_tree(vector<string> S){
    ll H=S.size();
    ll W=S[0].size();

    vector<vector<ll>> val(H,vll(W,-1));
    ll cnt=0;
    rep(h,H)rep(w,W){
        if(val[h][w]!=-1)continue;
        queue<pair<ll,ll>> Q;
        Q.push({h,w});
        val[h][w]=cnt;
        while(!Q.empty()){
            ll y=Q.front().first;
            ll x=Q.front().second;
            Q.pop();
            ll ds=4;
            if(S[y][x]=='#')ds=8;
            rep(d,ds){
                ll ny=y+dy[d];
                ll nx=x+dx[d];
                if(ny<0||nx<0||ny>=H||nx>=W)continue;
                if(S[ny][nx]!=S[y][x])continue;
                if(val[ny][nx]!=-1)continue;
                val[ny][nx]=cnt;
                Q.push({ny,nx});
            }
        }
        cnt++;
    }

    // rep(h,H){
    //     rep(w,W){
    //         cout<<val[h][w];
    //     }
    //     cout<<endl;
    // }

    vector<vll> G(cnt);
    vector<set<ll>> seen(cnt);
    rep(i,cnt)seen[i].insert(i);
    rep(h,H)rep(w,W){
        if(w!=W-1){
            if(!seen[val[h][w]].count(val[h][w+1])){
                G[val[h][w]].push_back(val[h][w+1]);
                seen[val[h][w]].insert(val[h][w+1]);
            }
        }
        if(h!=H-1){
            if(!seen[val[h][w]].count(val[h+1][w])){
                G[val[h][w]].push_back(val[h+1][w]);
                seen[val[h][w]].insert(val[h+1][w]);
            }
        }
    }
    return G;


}

using ull=unsigned long long;
struct TreeHasher{
    using uint128=__uint128_t;
    static const ull Mod=(1ull<<61ull)-1;
    static inline ull add(ull a,ull b){if((a+=b)>=Mod)a-=Mod;return a;}
    static inline ull mul(ull a,ull b){uint128 c=(uint128)a*b;return add(c>>61,c&Mod);}
    vector<ull> R;
    // 木のサイズ
    TreeHasher(int n){
        R.push_back(1);
        mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
        uniform_int_distribution<ull> rand(1,Mod-1);
        for(int i=1;i<=n;i++) R.push_back(rand(mt));
        // R.resize(n+1);
        // iota(ALL(R),1);
    }
    inline vector<int> BFS(vector<vector<int>> &g,int st,vector<int> &dis,bool memo_parent=false){
        vector<int> par;
        if(memo_parent) par.assign(g.size(),-1);
        dis.assign(g.size(),-1);
        dis[st]=0;
        queue<int> que;
        que.push(st);
        while(!que.empty()){
            int cur=que.front();que.pop();
            for(auto &to:g[cur]){
                if(dis[to]>=0) continue;
                dis[to]=dis[cur]+1;
                if(memo_parent) par[to]=cur;
                que.push(to);
            }
        }
        return par;
    }

    ull RootedTreeHash(vector<vector<ll>> &g,int root){
        vector<int> dis(g.size(),-1);
        vector<ull> h(g.size());
        function<void(int,int)> dfs=[&](int par,int cur){
            int d=-1;
            for(auto &to:g[cur])if(par!=to){
                dfs(cur,to);
                d=max(d,dis[to]);
            }
            d++;
            dis[cur]=d;
            ull ret=1;
            // rng hash
            for(auto &to:g[cur])if(par!=to) ret=mul(ret,add(h[to],R[d]));
            h[cur]=ret;
        };
        dfs(-1,root);
        return h[root];
    }
    bool RootedTreeIsomorphic(vector<vector<ll>> &g,int g_root,vector<vector<ll>> &h,int h_root){
        if(g.size()!=h.size()) return false;
        return (RootedTreeHash(g,g_root)==RootedTreeHash(h,h_root));
    }
};


void solve(ll H,ll W) {
    vector<vector<vll>> G(2); 
    rep(i,2){
        vector<string> S(H+2);
        rep(w,W+2){
            S[0].push_back('.');
            S[H+1].push_back('.');
        }
        rep(h,H){
            cin>>S[h+1];
            S[h+1]="."+S[h+1]+".";
        }

        G[i]=to_tree(S);

        if(i==0)cin>>H>>W;
    }
    if(G[0].size()!=G[1].size()){
        cout<<"no"<<endl;
        return;
    }
    TreeHasher T(G[0].size());
    cout<<(T.RootedTreeIsomorphic(G[0],0,G[1],0)?"yes":"no")<<endl;
}

int main() {

    ll H,W;

    while (cin >> H>>W) {
        if (H+W == 0)return 0;
        solve(H,W);
    }
}
accuracy: 1
time_ms: 50
memory_kb: 3736
final_rank: 4

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>

#ifdef DEFINED_ONLY_IN_LOCAL
#include "../cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

const long long INF = 1e9;
const long long MOD1 = 1e9 + 7;
const long long MOD2 = 998244353;
const long long LINF = 1e18;
using namespace std;
// using namespace atcoder;

#define YES(n) cout << ((n) ? "YES" : "NO") << endl
#define Yes(n) cout << ((n) ? "yes" : "no") << endl
#define POSSIBLE(n) cout << ((n) ? "POSSIBLE" : "IMPOSSIBLE") << endl
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << endl
#define Takahashi(n) cout << ((n) ? "Takahashi" : "Aoki") << endl
#define TAKAHASHI(n) cout << ((n) ? "TAKAHASHI" : "AOKI") << endl
#define First(n) cout << ((n) ? "First" : "Second") << endl
#define FIRST(n) cout << ((n) ? "FIRST" : "SECOND") << endl
#define COUT(x) cout << (x) << endl
#define SCOUT(x) cout << (x) << " "
#define VECCOUT(x)                              \
  for (auto &youso_ : (x))                      \
    cout << right << setw(10) << youso_ << " "; \
  cout << endl
#define ENDL cout << endl
#define CIN(...)   \
  int __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define LCIN(...)        \
  long long __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define SCIN(...)     \
  string __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define VECCIN(x)          \
  for (auto &youso_ : (x)) \
  cin >> youso_
#define mp make_pair

typedef long long ll;
typedef vector<long long> vl;
typedef vector<vl> vvl;
typedef pair<long long, long long> pll;

#define COUT(x) cout << (x) << endl
void CINT()
{
}
template <class Head, class... Tail>
void CINT(Head &&head, Tail &&...tail)
{
  cin >> head;
  CINT(move(tail)...);
}

// using mint = modint998244353;
// ostream& operator<< (ostream& os, const mint &x) {os << x.val(); return os;}

vvl solve(int h, int w, vvl &children)
{

  vector<string> S(h);

  VECCIN(S);
  ll count = -LINF;
  for (ll i = 0; i < h; i++)
    for (ll j = 0; j < w; j++)
      if (i * j == 0 || i == h - 1 || j == w - 1)
        if (S.at(i).at(j) == '#')
          count++;
  vvl m(h + 2, vl(w + 2, (count == h * w - (h - 2) * (w - 2)) ? -2 : (-1)));
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      m.at(i + 1).at(j + 1) = S.at(i).at(j) == '#' ? -2 : -1;
    }
  }
  int u_id = 0;
  // vvl children;
  set<pair<int, int>> s;
  for (ll i = 0; i < h + 2; i++)
    for (ll j = 0; j < w + 2; j++)
    {
      queue<pair<int, int>> q_outer;
      if (m.at(i).at(j) < 0)
      {
        q_outer.push(mp(i, j));
      }
      while (q_outer.size())
      {
        int q_outer_i, q_outer_j;
        tie(q_outer_i, q_outer_j) = q_outer.front();
        q_outer.pop();
        if (m.at(q_outer_i).at(q_outer_j) >= 0)
          continue;
        children.push_back(vl());
        bool is_black = m.at(q_outer_i).at(q_outer_j) == -2;
        int now = m.at(q_outer_i).at(q_outer_j);
        m.at(q_outer_i).at(q_outer_j) = u_id;
        // dump(now);
        queue<pair<int, int>> q;
        q.push(mp(q_outer_i, q_outer_j));
        while (q.size())
        {
          int ni, nj;
          tie(ni, nj) = q.front();
          q.pop();
          for (int next_i = ni - 1; next_i <= ni + 1; next_i++)
            for (int next_j = nj - 1; next_j <= nj + 1; next_j++)
              if (0 <= next_i && next_i < h + 2 && 0 <= next_j && next_j < w + 2)
              {
                int mdist = abs(next_i - ni) + abs(next_j - nj);
                if ((mdist == 1 && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id) ||
                    (mdist == 2 && is_black && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id))
                {
                  int child = u_id;
                  int parent = m.at(next_i).at(next_j);
                  if (s.count(mp(parent, child)) == false)
                    children.at(parent).push_back(child);
                  s.insert(mp(parent, child));
                }
                if (mdist == 1 && m.at(next_i).at(next_j) == now)
                {
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)
                {
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
              }
        }
        u_id++;
      }
    }
  return m;
}

ll hs(vvl &m, int now)
{
  ll res = 1;
  for (size_t i = 0; i < m.at(now).size(); i++)
  {
    res *= hs(m, m.at(now).at(i));
    res %= MOD1;
  }

  res += 37;
  res *= MOD2;
  res %= MOD1;
  return res;
}

void Main()
{
  while (1)
  {
    LCIN(h_1, w_1);
    if (h_1 == 0)
      break;
    vvl children_1;
    vvl res1 = solve(h_1, w_1, children_1);
    LCIN(h_2, w_2);
    vvl children_2;
    vvl res2 = solve(h_2, w_2, children_2);
    // dump(res1, res2)
    // dump(children_1, children_2);
    // dump(res1, res2);
    ll h1 = hs(children_1, 0);
    ll h2 = hs(children_2, 0);
    // dump(h1, h2);
    Yes(h1 == h2);
  }
}
int main()
{
  cout << fixed << setprecision(15);
  Main();
  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3744
final_rank: 13

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>

#ifdef DEFINED_ONLY_IN_LOCAL
#include "../cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

const long long INF = 1e9;
const long long MOD1 = 1e9 + 7;
const long long MOD2 = 998244353;
const long long LINF = 1e18;
using namespace std;
// using namespace atcoder;

#define YES(n) cout << ((n) ? "YES" : "NO") << endl
#define Yes(n) cout << ((n) ? "yes" : "no") << endl
#define POSSIBLE(n) cout << ((n) ? "POSSIBLE" : "IMPOSSIBLE") << endl
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << endl
#define Takahashi(n) cout << ((n) ? "Takahashi" : "Aoki") << endl
#define TAKAHASHI(n) cout << ((n) ? "TAKAHASHI" : "AOKI") << endl
#define First(n) cout << ((n) ? "First" : "Second") << endl
#define FIRST(n) cout << ((n) ? "FIRST" : "SECOND") << endl
#define COUT(x) cout << (x) << endl
#define SCOUT(x) cout << (x) << " "
#define VECCOUT(x)                              \
  for (auto &youso_ : (x))                      \
    cout << right << setw(10) << youso_ << " "; \
  cout << endl
#define ENDL cout << endl
#define CIN(...)   \
  int __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define LCIN(...)        \
  long long __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define SCIN(...)     \
  string __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define VECCIN(x)          \
  for (auto &youso_ : (x)) \
  cin >> youso_
#define mp make_pair

typedef long long ll;
typedef vector<long long> vl;
typedef vector<vl> vvl;
typedef pair<long long, long long> pll;

#define COUT(x) cout << (x) << endl
void CINT()
{
}
template <class Head, class... Tail>
void CINT(Head &&head, Tail &&...tail)
{
  cin >> head;
  CINT(move(tail)...);
}

// using mint = modint998244353;
// ostream& operator<< (ostream& os, const mint &x) {os << x.val(); return os;}

vvl solve(int h, int w, vvl &children)
{

  vector<string> S(h);

  VECCIN(S);
  ll count = -LINF;
  for (ll i = 0; i < h; i++)
    for (ll j = 0; j < w; j++)
      if (i * j == 0 || i == h - 1 || j == w - 1)
        if (S.at(i).at(j) == '#')
          count++;
  vvl m(h + 2, vl(w + 2, (count == h * w - (h - 2) * (w - 2)) ? -2 : (-1)));
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      dump(i, j, S);
      m.at(i + 1).at(j + 1) = S.at(i).at(j) == '#' ? -2 : -1;
    }
  }
  int u_id = 0;
  // vvl children;
  set<pair<int, int>> s;
  for (ll i = 0; i < h + 2; i++)
    for (ll j = 0; j < w + 2; j++)
    {
      queue<pair<int, int>> q_outer;
      if (m.at(i).at(j) < 0)
      {
        q_outer.push(mp(i, j));
      }
      while (q_outer.size())
      {
        int q_outer_i, q_outer_j;
        tie(q_outer_i, q_outer_j) = q_outer.front();
        q_outer.pop();
        if (m.at(q_outer_i).at(q_outer_j) >= 0)
          continue;
        children.push_back(vl());
        bool is_black = m.at(q_outer_i).at(q_outer_j) == -2;
        int now = m.at(q_outer_i).at(q_outer_j);
        m.at(q_outer_i).at(q_outer_j) = u_id;
        dump(m);
        queue<pair<int, int>> q;
        q.push(mp(q_outer_i, q_outer_j));
        while (q.size())
        {
          int ni, nj;
          tie(ni, nj) = q.front();
          q.pop();
          for (int next_i = ni - 1; next_i <= ni + 1; next_i++)
            for (int next_j = nj - 1; next_j <= nj + 1; next_j++)
              if (0 <= next_i && next_i < h + 2 && 0 <= next_j && next_j < w + 2)
              {
                int mdist = abs(next_i - ni) + abs(next_j - nj);
                if ((mdist == 1 && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id) ||
                    (mdist == 2 && is_black && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id))
                {
                  int child = u_id;
                  int parent = m.at(next_i).at(next_j);
                  if (s.count(mp(parent, child)) == false)
                    children.at(parent).push_back(child);
                  s.insert(mp(parent, child));
                }
                // if (m.at(next_i).at(next_j) < 0)
                // {
                //   q_outer.push(mp(next_i, next_j));
                // }
                // dump(next_i, next_j);
                if (mdist == 1 && m.at(next_i).at(next_j) == now)
                {
                  // dump("                if (mdist == 1 && m.at(next_i).at(next_j) == now)");
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)
                {
                  // dump("                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)");
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
              }
        }
        u_id++;
      }
    }
  return m;
}

ll hs(vvl &m, int now)
{
  ll res = 1;
  for (size_t i = 0; i < m.at(now).size(); i++)
  {
    res *= hs(m, m.at(now).at(i));
    res %= MOD1;
  }

  res += 37;
  res *= MOD2;
  res %= MOD1;
  return res;
}

void Main()
{
  while (1)
  {
    LCIN(h_1, w_1);
    if (h_1 == 0)
      break;
    vvl children_1;
    vvl res1 = solve(h_1, w_1, children_1);
    LCIN(h_2, w_2);
    vvl children_2;
    vvl res2 = solve(h_2, w_2, children_2);
    dump(res1, res2);
    dump(children_1, children_2);
    ll h1 = hs(children_1, 0);
    ll h2 = hs(children_2, 0);
    dump(h1, h2);
    Yes(h1 == h2);
  }
}
int main()
{
  cout << fixed << setprecision(15);
  Main();
  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3696
final_rank: 12

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>

#ifdef DEFINED_ONLY_IN_LOCAL
#include "../cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

const long long INF = 1e9;
const long long MOD1 = 1e9 + 7;
const long long MOD2 = 998244353;
const long long LINF = 1e18;
using namespace std;
// using namespace atcoder;

#define YES(n) cout << ((n) ? "YES" : "NO") << endl
#define Yes(n) cout << ((n) ? "yes" : "no") << endl
#define POSSIBLE(n) cout << ((n) ? "POSSIBLE" : "IMPOSSIBLE") << endl
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << endl
#define Takahashi(n) cout << ((n) ? "Takahashi" : "Aoki") << endl
#define TAKAHASHI(n) cout << ((n) ? "TAKAHASHI" : "AOKI") << endl
#define First(n) cout << ((n) ? "First" : "Second") << endl
#define FIRST(n) cout << ((n) ? "FIRST" : "SECOND") << endl
#define COUT(x) cout << (x) << endl
#define SCOUT(x) cout << (x) << " "
#define VECCOUT(x)                              \
  for (auto &youso_ : (x))                      \
    cout << right << setw(10) << youso_ << " "; \
  cout << endl
#define ENDL cout << endl
#define CIN(...)   \
  int __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define LCIN(...)        \
  long long __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define SCIN(...)     \
  string __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define VECCIN(x)          \
  for (auto &youso_ : (x)) \
  cin >> youso_
#define mp make_pair

typedef long long ll;
typedef vector<long long> vl;
typedef vector<vl> vvl;
typedef pair<long long, long long> pll;

#define COUT(x) cout << (x) << endl
void CINT()
{
}
template <class Head, class... Tail>
void CINT(Head &&head, Tail &&...tail)
{
  cin >> head;
  CINT(move(tail)...);
}

// using mint = modint998244353;
// ostream& operator<< (ostream& os, const mint &x) {os << x.val(); return os;}

vvl solve(int h, int w, vvl &children)
{

  vector<string> S(h);

  VECCIN(S);
  ll count = -LINF;
  for (ll i = 0; i < h; i++)
    for (ll j = 0; j < w; j++)
      if (i * j == 0 || i == h - 1 || j == w - 1)
        if (S.at(i).at(j) == '#')
          count++;
  vvl m(h + 2, vl(w + 2, (count == h * w - (h - 2) * (w - 2)) ? -2 : (-1)));
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      dump(i, j, S);
      m.at(i + 1).at(j + 1) = S.at(i).at(j) == '#' ? -2 : -1;
    }
  }
  int u_id = 0;
  // vvl children;
  set<pair<int, int>> s;
  for (ll i = 0; i < h + 2; i++)
    for (ll j = 0; j < w + 2; j++)
    {
      queue<pair<int, int>> q_outer;
      if (m.at(i).at(j) < 0)
      {
        q_outer.push(mp(i, j));
      }
      while (q_outer.size())
      {
        int q_outer_i, q_outer_j;
        tie(q_outer_i, q_outer_j) = q_outer.front();
        q_outer.pop();
        if (m.at(q_outer_i).at(q_outer_j) >= 0)
          continue;
        children.push_back(vl());
        bool is_black = m.at(q_outer_i).at(q_outer_j) == -2;
        int now = m.at(q_outer_i).at(q_outer_j);
        m.at(q_outer_i).at(q_outer_j) = u_id;
        dump(m);
        queue<pair<int, int>> q;
        q.push(mp(q_outer_i, q_outer_j));
        while (q.size())
        {
          int ni, nj;
          tie(ni, nj) = q.front();
          q.pop();
          for (int next_i = ni - 1; next_i <= ni + 1; next_i++)
            for (int next_j = nj - 1; next_j <= nj + 1; next_j++)
              if (0 <= next_i && next_i < h + 2 && 0 <= next_j && next_j < w + 2)
              {
                int mdist = abs(next_i - ni) + abs(next_j - nj);
                if ((mdist == 1 && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id) ||
                    (mdist == 2 && is_black && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id))
                {
                  int child = u_id;
                  int parent = m.at(next_i).at(next_j);
                  if (s.count(mp(parent, child)) == false)
                    children.at(parent).push_back(child);
                  s.insert(mp(parent, child));
                }
                // if (m.at(next_i).at(next_j) < 0)
                // {
                //   q_outer.push(mp(next_i, next_j));
                // }
                // dump(next_i, next_j);
                if (mdist == 1 && m.at(next_i).at(next_j) == now)
                {
                  // dump("                if (mdist == 1 && m.at(next_i).at(next_j) == now)");
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)
                {
                  // dump("                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)");
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
              }
        }
        u_id++;
      }
    }
  return m;
}

string hs(vvl &m, int now)
{
  string res = "";
  vector<string> S;
  for (size_t i = 0; i < m.at(now).size(); i++)
  {
    S.push_back(hs(m, m.at(now).at(i)));
  }
  sort(S.begin(), S.end());
  for (size_t i = 0; i < m.at(now).size(); i++)
    res += S.at(i);

  return '(' + res + ')';
}

void Main()
{
  while (1)
  {
    LCIN(h_1, w_1);
    if (h_1 == 0)
      break;
    vvl children_1;
    vvl res1 = solve(h_1, w_1, children_1);
    LCIN(h_2, w_2);
    vvl children_2;
    vvl res2 = solve(h_2, w_2, children_2);
    dump(res1, res2);
    dump(children_1, children_2);
    string h1 = hs(children_1, 0);
    string h2 = hs(children_2, 0);
    dump(h1, h2);
    Yes(h1 == h2);
  }
}
int main()
{
  cout << fixed << setprecision(15);
  Main();
  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 3656
final_rank: 11

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>

#ifdef DEFINED_ONLY_IN_LOCAL
#include "../cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

const long long INF = 1e9;
const long long MOD1 = 1e9 + 7;
const long long MOD2 = 998244353;
const long long LINF = 1e18;
using namespace std;
// using namespace atcoder;

#define YES(n) cout << ((n) ? "YES" : "NO") << endl
#define Yes(n) cout << ((n) ? "yes" : "no") << endl
#define POSSIBLE(n) cout << ((n) ? "POSSIBLE" : "IMPOSSIBLE") << endl
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << endl
#define Takahashi(n) cout << ((n) ? "Takahashi" : "Aoki") << endl
#define TAKAHASHI(n) cout << ((n) ? "TAKAHASHI" : "AOKI") << endl
#define First(n) cout << ((n) ? "First" : "Second") << endl
#define FIRST(n) cout << ((n) ? "FIRST" : "SECOND") << endl
#define COUT(x) cout << (x) << endl
#define SCOUT(x) cout << (x) << " "
#define VECCOUT(x)                              \
  for (auto &youso_ : (x))                      \
    cout << right << setw(10) << youso_ << " "; \
  cout << endl
#define ENDL cout << endl
#define CIN(...)   \
  int __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define LCIN(...)        \
  long long __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define SCIN(...)     \
  string __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define VECCIN(x)          \
  for (auto &youso_ : (x)) \
  cin >> youso_
#define mp make_pair

typedef long long ll;
typedef vector<long long> vl;
typedef vector<vl> vvl;
typedef pair<long long, long long> pll;

#define COUT(x) cout << (x) << endl
void CINT()
{
}
template <class Head, class... Tail>
void CINT(Head &&head, Tail &&...tail)
{
  cin >> head;
  CINT(move(tail)...);
}

// using mint = modint998244353;
// ostream& operator<< (ostream& os, const mint &x) {os << x.val(); return os;}

vvl solve(int h, int w, vvl &children)
{

  vector<string> S(h);

  VECCIN(S);
  ll count = 0;
  for (ll i = 0; i < h; i++)
    for (ll j = 0; j < w; j++)
      if (i * j == 0 || i == h - 1 || j == w - 1)
        if (S.at(i).at(j) == '#')
          count++;
  vvl m(h + 2, vl(w + 2, (count == h * w - (h - 2) * (w - 2)) ? -2 : (-1)));
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      m.at(i + 1).at(j + 1) = S.at(i).at(j) == '#' ? -2 : -1;
    }
  }
  int u_id = 0;
  // vvl children;
  set<pair<int, int>> s;
  for (ll i = 0; i < h + 2; i++)
    for (ll j = 0; j < w + 2; j++)
    {
      queue<pair<int, int>> q_outer;
      if (m.at(i).at(j) < 0)
      {
        q_outer.push(mp(i, j));
      }
      while (q_outer.size())
      {
        int q_outer_i, q_outer_j;
        tie(q_outer_i, q_outer_j) = q_outer.front();
        q_outer.pop();
        if (m.at(q_outer_i).at(q_outer_j) >= 0)
          continue;
        children.push_back(vl());
        bool is_black = m.at(q_outer_i).at(q_outer_j) == -2;
        int now = m.at(q_outer_i).at(q_outer_j);
        m.at(q_outer_i).at(q_outer_j) = u_id;
        // dump(now);
        queue<pair<int, int>> q;
        q.push(mp(q_outer_i, q_outer_j));
        while (q.size())
        {
          int ni, nj;
          tie(ni, nj) = q.front();
          q.pop();
          for (int next_i = ni - 1; next_i <= ni + 1; next_i++)
            for (int next_j = nj - 1; next_j <= nj + 1; next_j++)
              if (0 <= next_i && next_i < h + 2 && 0 <= next_j && next_j < w + 2)
              {
                int mdist = abs(next_i - ni) + abs(next_j - nj);
                if ((mdist == 1 && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id) ||
                    (mdist == 2 && is_black && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id))
                {
                  int child = u_id;
                  int parent = m.at(next_i).at(next_j);
                  if (s.count(mp(parent, child)) == false)
                    children.at(parent).push_back(child);
                  s.insert(mp(parent, child));
                }
                if (mdist == 1 && m.at(next_i).at(next_j) == now)
                {
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)
                {
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
              }
        }
        u_id++;
      }
    }
  return m;
}

string hs(vvl &m, int now)
{
  string res = "";
  vector<string> S;
  for (size_t i = 0; i < m.at(now).size(); i++)
  {
    S.push_back(hs(m, m.at(now).at(i)));
  }
  sort(S.begin(), S.end());
  for (size_t i = 0; i < m.at(now).size(); i++)
    res += S.at(i);

  return '(' + res + ')';
}

void Main()
{
  while (1)
  {
    LCIN(h_1, w_1);
    if (h_1 == 0)
      break;
    vvl children_1;
    vvl res1 = solve(h_1, w_1, children_1);
    LCIN(h_2, w_2);
    vvl children_2;
    vvl res2 = solve(h_2, w_2, children_2);
    // dump(res1, res2)
    // dump(children_1, children_2);
    // dump(res1, res2);
    string h1 = hs(children_1, 0);
    string h2 = hs(children_2, 0);
    // dump(h1, h2);
    Yes(h1 == h2);
  }
}
int main()
{
  cout << fixed << setprecision(15);
  Main();
  return 0;
}
accuracy: 0.5
time_ms: 80
memory_kb: 3672
final_rank: 20

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>

#ifdef DEFINED_ONLY_IN_LOCAL
#include "../cpp-dump/dump.hpp"
#define dump(...) cpp_dump(__VA_ARGS__)
namespace cp = cpp_dump;
#else
#define dump(...)
#define CPP_DUMP_SET_OPTION(...)
#define CPP_DUMP_DEFINE_EXPORT_OBJECT(...)
#define CPP_DUMP_DEFINE_EXPORT_ENUM(...)
#define CPP_DUMP_DEFINE_DANGEROUS_EXPORT_OBJECT(...)
#endif

const long long INF = 1e9;
const long long MOD1 = 1e9 + 7;
const long long MOD2 = 998244353;
const long long LINF = 1e18;
using namespace std;
// using namespace atcoder;

#define YES(n) cout << ((n) ? "YES" : "NO") << endl
#define Yes(n) cout << ((n) ? "yes" : "no") << endl
#define POSSIBLE(n) cout << ((n) ? "POSSIBLE" : "IMPOSSIBLE") << endl
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << endl
#define Takahashi(n) cout << ((n) ? "Takahashi" : "Aoki") << endl
#define TAKAHASHI(n) cout << ((n) ? "TAKAHASHI" : "AOKI") << endl
#define First(n) cout << ((n) ? "First" : "Second") << endl
#define FIRST(n) cout << ((n) ? "FIRST" : "SECOND") << endl
#define COUT(x) cout << (x) << endl
#define SCOUT(x) cout << (x) << " "
#define VECCOUT(x)                              \
  for (auto &youso_ : (x))                      \
    cout << right << setw(10) << youso_ << " "; \
  cout << endl
#define ENDL cout << endl
#define CIN(...)   \
  int __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define LCIN(...)        \
  long long __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define SCIN(...)     \
  string __VA_ARGS__; \
  CINT(__VA_ARGS__)
#define VECCIN(x)          \
  for (auto &youso_ : (x)) \
  cin >> youso_
#define mp make_pair

typedef long long ll;
typedef vector<long long> vl;
typedef vector<vl> vvl;
typedef pair<long long, long long> pll;

#define COUT(x) cout << (x) << endl
void CINT()
{
}
template <class Head, class... Tail>
void CINT(Head &&head, Tail &&...tail)
{
  cin >> head;
  CINT(move(tail)...);
}

// using mint = modint998244353;
// ostream& operator<< (ostream& os, const mint &x) {os << x.val(); return os;}

vvl solve(int h, int w, vvl &children)
{

  vector<string> S(h);

  VECCIN(S);
  ll count = 0;
  for (ll i = 0; i < h; i++)
    for (ll j = 0; j < w; j++)
      if (i * j == 0 || i == h - 1 || j == w - 1)
        if (S.at(i).at(j) == '#')
          count++;
  vvl m(h + 2, vl(w + 2, (count == h * w - (h - 2) * (w - 2)) ? -2 : (-1)));
  for (ll i = 0; i < h; i++)
  {
    for (ll j = 0; j < w; j++)
    {
      m.at(i + 1).at(j + 1) = S.at(i).at(j) == '#' ? -2 : -1;
    }
  }
  int u_id = 0;
  // vvl children;
  set<pair<int, int>> s;
  for (ll i = 0; i < h + 2; i++)
    for (ll j = 0; j < w + 2; j++)
    {
      queue<pair<int, int>> q_outer;
      if (m.at(i).at(j) < 0)
      {
        q_outer.push(mp(i, j));
      }
      while (q_outer.size())
      {
        int q_outer_i, q_outer_j;
        tie(q_outer_i, q_outer_j) = q_outer.front();
        q_outer.pop();
        if (m.at(q_outer_i).at(q_outer_j) >= 0)
          continue;
        children.push_back(vl());
        bool is_black = m.at(q_outer_i).at(q_outer_j) == -2;
        int now = m.at(q_outer_i).at(q_outer_j);
        m.at(q_outer_i).at(q_outer_j) = u_id;
        // dump(now);
        queue<pair<int, int>> q;
        q.push(mp(q_outer_i, q_outer_j));
        while (q.size())
        {
          int ni, nj;
          tie(ni, nj) = q.front();
          q.pop();
          for (int next_i = ni - 1; next_i <= ni + 1; next_i++)
            for (int next_j = nj - 1; next_j <= nj + 1; next_j++)
              if (0 <= next_i && next_i < h + 2 && 0 <= next_j && next_j < w + 2)
              {
                int mdist = abs(next_i - ni) + abs(next_j - nj);
                if ((mdist == 1 && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id) ||
                    (mdist == 2 && is_black && m.at(next_i).at(next_j) >= 0 && m.at(next_i).at(next_j) < u_id))
                {
                  int child = u_id;
                  int parent = m.at(next_i).at(next_j);
                  if (s.count(mp(parent, child)) == false)
                    children.at(parent).push_back(child);
                  s.insert(mp(parent, child));
                }
                if (mdist == 1 && m.at(next_i).at(next_j) == now)
                {
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
                if (mdist == 2 && is_black && m.at(next_i).at(next_j) == now)
                {
                  m.at(next_i).at(next_j) = u_id;
                  q.push(mp(next_i, next_j));
                }
              }
        }
        u_id++;
      }
    }
  return m;
}

ll hs(vvl &m, int now)
{
  ll res = 1;
  for (size_t i = 0; i < m.at(now).size(); i++)
  {
    res *= hs(m, m.at(now).at(i));
    res %= MOD1;
  }

  res += 37;
  res *= MOD2;
  res %= MOD1;
  return res;
}

void Main()
{
  while (1)
  {
    LCIN(h_1, w_1);
    if (h_1 == 0)
      break;
    vvl children_1;
    vvl res1 = solve(h_1, w_1, children_1);
    LCIN(h_2, w_2);
    vvl children_2;
    vvl res2 = solve(h_2, w_2, children_2);
    // dump(res1, res2)
    // dump(children_1, children_2);
    // dump(res1, res2);
    ll h1 = hs(children_1, 0);
    ll h2 = hs(children_2, 0);
    // dump(h1, h2);
    Yes(h1 == h2);
  }
}
int main()
{
  cout << fixed << setprecision(15);
  Main();
  return 0;
}
accuracy: 0.5
time_ms: 80
memory_kb: 3652
final_rank: 19

code_snippet: #include<iostream>
#include<vector>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
int dy4[4] = {1,0,-1,0};
int dx4[4] = {0,1,0,-1};
int dy8[8] = {1,1,1,0,-1,-1,-1,0};
int dx8[8] = {-1,0,1,1,1,0,-1,-1};
bool inr(int l, int x, int r){
  return (l <= x) && (x < r);
}
void dfs(int now, vector<set<int>> &G, vector<string> &str, vector<bool> &seen){
  seen[now] = true;
  vector<string> tmp;
  for(int next:G[now]){
    if(seen[next])continue;
    dfs(next, G, str, seen);
    tmp.push_back(str[next]);
  }
  sort(tmp.begin(), tmp.end());
  str[now] = "(";
  for(int i = 0; i < (int)tmp.size(); i++){
    str[now] += tmp[i];
  }
  str[now] += ")";
  return;
}
string graph_to_string(vector<set<int>> G){
  vector<string> str(G.size());
  vector<bool> seen(G.size(), false);
  // 木を括弧からなる文字列に変換する
  dfs(0, G, str, seen);
  return str[0];
}
vector<set<int>> pixel_to_graph(int h, int w, vector<string> P){
  // 画像の周りに白のピクセルを追加する
  for(int i = 0; i < h; i++){
    P[i] = "." + P[i] + ".";
  }
  {
    string tmp(w+2, '.');
    P.insert(P.begin(), tmp);
    P.push_back(tmp);
  }
  // ピクセルを幅優先探索で連結成分分解
  int cnt = 0;
  vector<vector<int>> comp(h+2, vector<int>(w+2, -1));
  for(int i = 0; i < h+2; i++){
    for(int j = 0; j < w+2; j++){
      if(comp[i][j] == -1){
        char color = P[i][j];
        queue<pair<int,int>> qu;
        qu.push(make_pair(i,j));
        comp[i][j] = cnt;
        while(!qu.empty()){
          pair<int,int> now = qu.front();
          qu.pop();
          for(int d = 0; d < 8; d++){
            int ny, nx;
            if(color == '.'){ // 白の場合
              if(4 <= d)break;
              ny = now.first + dy4[d];
              nx = now.second + dx4[d];
            }else{ // 黒の場合
              ny = now.first + dy8[d];
              nx = now.second + dx8[d];
            }
            if(!inr(0, ny ,h+2) || !inr(0, nx ,w+2))continue;
            if(P[ny][nx] != color || comp[ny][nx] != -1)continue;
            qu.push(make_pair(ny,nx));
            comp[ny][nx] = cnt;
          }
        }
        cnt++;
      }
    }
  }
  // 連結成分同士の位置関係をグラフに変換する
  vector<set<int>> G(cnt);
  for(int i = 0; i < h+2; i++){
    for(int j = 0; j < w+2; j++){
      if(i+1 < h+2){
        if(comp[i][j] != comp[i+1][j]){
          G[comp[i][j]].insert(comp[i+1][j]);
          G[comp[i+1][j]].insert(comp[i][j]);
        }
      }
      if(j+1 < w+2){
        if(comp[i][j] != comp[i][j+1]){
          G[comp[i][j]].insert(comp[i][j+1]);
          G[comp[i][j+1]].insert(comp[i][j]);
        }
      }
    }
  }
  return G;
}
int main(){
  while(1){
    int h[2],w[2];
    vector<string> P[2];
    // 画像1 入力
    cin >> h[0] >> w[0];
    if(h[0] == 0 && w[0] == 0)break; // データセットの終わり
    P[0].resize(h[0]);
    for(int i = 0; i < h[0]; i++){
      cin >> P[0][i];
    }

    // 画像2 入力
    cin >> h[1] >> w[1];
    P[1].resize(h[1]);
    for(int i = 0; i < h[1]; i++){
      cin >> P[1][i];
    }

    // 出力
    if(graph_to_string(pixel_to_graph(h[0],w[0],P[0])) == graph_to_string(pixel_to_graph(h[1],w[1],P[1]))){
      cout << "yes" << endl;
    }else{
      cout << "no" << endl;
    }
  }
}
accuracy: 1
time_ms: 50
memory_kb: 3568
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define ALL(v) v.begin(),v.end()
#define dbg(x) cerr << #x << ": " << (x) << endl;
template<class F, class S>
ostream& operator<<(ostream& os, pair<F,S>& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template<class Iter>
void print(Iter beg, Iter end) {
    for (Iter itr = beg; itr != end; ++itr) {
        cerr << *itr << ' ';
    }
    cerr << '\n';
}
using Pic = vector<vector<char>>;
using Graph = vector<vector<int>>;
Pic S[2];
int dx[] = {1,0,-1,0,1};

vector<pair<int,int>> paintConnected(const Pic& p, vector<vector<int>>& col, int sx, int sy, int idx) {
    vector<pair<int,int>> inside;
    int h = p.size();
    int w = p[0].size();
    queue<pair<int,int>> q;
    q.emplace(sx, sy);
    col[sx][sy] = idx;
    while (q.size()) {
        auto [x,y] = q.front();
        q.pop();
        
        if (p[sx][sy] == '.') {
            for (int i = 0; i < 4; ++i) {
                int nx = x + dx[i];
                int ny = y + dx[i+1];
                if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                if (col[nx][ny] != -1) continue;
                if (p[nx][ny] != p[sx][sy]) {
                    if (col[nx][ny] == -1) inside.emplace_back(nx, ny);
                    continue;
                }
                q.emplace(nx, ny);
                col[nx][ny] = idx;
            }
        } else {
            for (int dx = -1; dx < 2; ++dx) {
                for (int dy = -1; dy < 2; ++dy) {
                    if (dx==0 && dy==0) continue;
                    int nx = x + dx;
                    int ny = y + dy;
                    if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                    if (col[nx][ny] != -1) continue;
                    if (p[nx][ny] != p[sx][sy]) {
                        if (col[nx][ny] == -1) inside.emplace_back(nx, ny);
                        continue;
                    }
                    q.emplace(nx, ny);
                    col[nx][ny] = idx;
                }
            }
        }
    }
    return inside;
}

pair<vector<vector<int>>, int> paint(const Pic& p) {
    int h = p.size();
    int w = p[0].size();
    queue<pair<int,int>> q;
    vector<vector<int>> col(h, vector<int>(w,-1));
    int idx = 0;
    q.emplace(0,0);

    while (q.size()) {
        auto [x,y] = q.front();
        q.pop();
        if (col[x][y] != -1) continue;

        auto inside = paintConnected(p, col, x, y, idx);
        for (auto x : inside) {
            q.push(x);
        }
        ++idx;
    }
    return {col, idx};
}

Graph gen(const Pic& p, vector<vector<int>>& col, int kind) {
    int h = col.size();
    int w = col[0].size();

    set<pair<int,int>> st;

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            for (int dx = -1; dx < 2; ++dx) {
                for (int dy = -1; dy < 2; ++dy) {
                    if (dx==0 && dy==0) continue;
                    int nx = i + dx;
                    int ny = j + dy;
                    if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                    int a = col[nx][ny];
                    int b = col[i][j];
                    if (p[i][j] == p[nx][ny]) continue;
                    if (a == b) continue;
                    if (a > b) swap(a,b);
                    st.emplace(a, b);
                }
            }
        }
    }
    Graph g(kind);
    for (auto [u,v] : st) {
        g[u].push_back(v);
        g[v].push_back(u);
    }
    return g;
}
// O(N + M)
pair<vector<int>, int> bfs(const Graph& g, int start) {
    int n = g.size();
    vector<int> dis(n, 1e9), pre(n, -1);
    queue<int> q;
    dis[start] = 0;
    q.push(start);
    int ma = 0;
    int farthest = start;
    while (q.size()) {
        int pos = q.front();
        q.pop();
        for (int to : g[pos]) {
            if (dis[pos] + 1 < dis[to]) {
                dis[to] = dis[pos] + 1;
                pre[to] = pos;
                q.push(to);
                if (dis[to] > ma) {
                    ma = dis[to];
                    farthest = to;
                }
            }
        }
    }
    return {pre, farthest};
}

// 木の中心を求める(木の直径の中央の頂点)
// 1or2頂点
vector<int> center(const Graph& tree) {
    auto [pre1, v1] = bfs(tree, 0);
    auto [pre2, v2] = bfs(tree, v1);

    vector<int> path;
    int now = v2;
    while (now != -1) {
        path.push_back(now);
        now = pre2[now];
    }

    vector<int> centers;
    centers.push_back(path[path.size() / 2]);
    if (path.size() % 2 == 0) centers.push_back(path[path.size() / 2 - 1]);
    return centers;
}
// 木の名前を求める
int name(int pos, int pre, const Graph& tree, map<vector<int>,int>& cmp, int& id) {
    vector<int> seq;
    for (int c : tree[pos]) {
        if (c == pre) continue;
        seq.push_back(name(c, pos, tree, cmp, id));
    }
    if (seq.empty()) {
        return 0;
    }
    sort(ALL(seq));
    if (cmp.count(seq)) {
        return cmp.at(seq);
    } else {
        cmp[seq] = ++id;
        return id;
    }
}
// 根付き木の同型性判定
bool isomorphism_rooted(const Graph& t1, const Graph& t2, int r1, int r2) {
    int id = 0;
    map<vector<int>, int> cmp;
    int name1 = name(r1, -1, t1, cmp, id);
    int name2 = name(r2, -1, t2, cmp, id);
    return (name1 == name2);
}

bool solve() {
    for (int t = 0; t < 2; ++t) {
        int h,w;
        cin >> h >> w;
        if (h+w == 0) exit(0);
        S[t].assign(h+2, vector<char>(w+2, '.'));
        for (int i = 1; i <= h; ++i) {
            for (int j = 1; j <= w; ++j) {
                cin >> S[t][i][j];
            }
        }
    }

    vector<vector<int>> col[2];
    int kind[2];
    for (int i = 0; i < 2; ++i) {
        tie(col[i], kind[i]) = paint(S[i]);
    }
    Graph g[2];
    for (int i = 0; i < 2; ++i) {
        g[i] = gen(S[i], col[i], kind[i]);
    }

    return isomorphism_rooted(g[0], g[1], 0, 0);
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    while (true) {
        cout << (solve() ? "yes" : "no")<< '\n';
    }
}
accuracy: 1
time_ms: 140
memory_kb: 3716
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define ALL(v) v.begin(),v.end()
#define dbg(x) cerr << #x << ": " << (x) << endl;
template<class F, class S>
ostream& operator<<(ostream& os, pair<F,S>& p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template<class Iter>
void print(Iter beg, Iter end) {
    for (Iter itr = beg; itr != end; ++itr) {
        cerr << *itr << ' ';
    }
    cerr << '\n';
}
using Pic = vector<vector<char>>;
using Graph = vector<vector<int>>;
Pic S[2];
int dx[] = {1,0,-1,0,1};

vector<pair<int,int>> paintConnected(const Pic& p, vector<vector<int>>& col, int sx, int sy, int idx) {
    vector<pair<int,int>> inside;
    int h = p.size();
    int w = p[0].size();
    queue<pair<int,int>> q;
    q.emplace(sx, sy);
    col[sx][sy] = idx;
    while (q.size()) {
        auto [x,y] = q.front();
        q.pop();
        
        if (p[sx][sy] == '.') {
            for (int i = 0; i < 4; ++i) {
                int nx = x + dx[i];
                int ny = y + dx[i+1];
                if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                if (col[nx][ny] != -1) continue;
                if (p[nx][ny] != p[sx][sy]) {
                    if (col[nx][ny] == -1) inside.emplace_back(nx, ny);
                    continue;
                }
                q.emplace(nx, ny);
                col[nx][ny] = idx;
            }
        } else {
            for (int dx = -1; dx < 2; ++dx) {
                for (int dy = -1; dy < 2; ++dy) {
                    if (dx==0 && dy==0) continue;
                    int nx = x + dx;
                    int ny = y + dy;
                    if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                    if (col[nx][ny] != -1) continue;
                    if (p[nx][ny] != p[sx][sy]) {
                        if (col[nx][ny] == -1) inside.emplace_back(nx, ny);
                        continue;
                    }
                    q.emplace(nx, ny);
                    col[nx][ny] = idx;
                }
            }
        }
    }
    return inside;
}

pair<vector<vector<int>>, int> paint(const Pic& p) {
    int h = p.size();
    int w = p[0].size();
    queue<pair<int,int>> q;
    vector<vector<int>> col(h, vector<int>(w,-1));
    int idx = 0;
    q.emplace(0,0);

    while (q.size()) {
        auto [x,y] = q.front();
        q.pop();
        if (col[x][y] != -1) continue;

        auto inside = paintConnected(p, col, x, y, idx);
        for (auto x : inside) {
            q.push(x);
        }
        ++idx;
    }
    return {col, idx};
}

Graph gen(const Pic& p, vector<vector<int>>& col, int kind) {
    int h = col.size();
    int w = col[0].size();

    set<pair<int,int>> st;

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            for (int dx = -1; dx < 2; ++dx) {
                for (int dy = -1; dy < 2; ++dy) {
                    if (dx==0 && dy==0) continue;
                    int nx = i + dx;
                    int ny = j + dy;
                    if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                    int a = col[nx][ny];
                    int b = col[i][j];
                    if (p[i][j] == p[nx][ny]) continue;
                    if (a == b) continue;
                    if (a > b) swap(a,b);
                    st.emplace(a, b);
                }
            }
        }
    }
    Graph g(kind);
    for (auto [u,v] : st) {
        g[u].push_back(v);
        g[v].push_back(u);
    }
    return g;
}
// O(N + M)
tuple<vector<int>, vector<int>, int> bfs(const Graph& g, int start) {
    int n = g.size();
    vector<int> dis(n, 1e9), pre(n, -1);
    queue<int> q;
    dis[start] = 0;
    q.push(start);
    int ma = 0;
    int farthest = start;
    while (q.size()) {
        int pos = q.front();
        q.pop();
        for (int to : g[pos]) {
            if (dis[pos] + 1 < dis[to]) {
                dis[to] = dis[pos] + 1;
                pre[to] = pos;
                q.push(to);
                if (dis[to] > ma) {
                    ma = dis[to];
                    farthest = to;
                }
            }
        }
    }
    return {dis, pre, farthest};
}

// 木の中心を求める(木の直径の中央の頂点)
// 1or2頂点
vector<int> center(const Graph& tree) {
    auto [dis1, pre1, v1] = bfs(tree, 0);
    auto [dis2, pre2, v2] = bfs(tree, v1);

    vector<int> path;
    int now = v2;
    while (now != -1) {
        path.push_back(now);
        now = pre2[now];
    }

    vector<int> centers;
    centers.push_back(path[path.size() / 2]);
    if (path.size() % 2 == 0) centers.push_back(path[path.size() / 2 - 1]);
    return centers;
}
// 木の名前を求める
int name(int pos, int pre, const Graph& tree, map<vector<int>,int>& cmp, int& id) {
    vector<int> seq;
    for (int c : tree[pos]) {
        if (c == pre) continue;
        seq.push_back(name(c, pos, tree, cmp, id));
    }
    if (seq.empty()) {
        return 0;
    }
    sort(ALL(seq));
    if (cmp.count(seq)) {
        return cmp.at(seq);
    } else {
        cmp[seq] = ++id;
        return id;
    }
}
// 根付き木の同型性判定
bool isomorphism_rooted(const Graph& t1, const Graph& t2, int r1, int r2) {
    int id = 0;
    map<vector<int>, int> cmp;
    int name1 = name(r1, -1, t1, cmp, id);
    int name2 = name(r2, -1, t2, cmp, id);
    return (name1 == name2);
}

bool solve() {
    for (int t = 0; t < 2; ++t) {
        int h,w;
        cin >> h >> w;
        if (h+w == 0) exit(0);
        S[t].assign(h+2, vector<char>(w+2, '.'));
        for (int i = 1; i <= h; ++i) {
            for (int j = 1; j <= w; ++j) {
                cin >> S[t][i][j];
            }
        }
    }

    vector<vector<int>> col[2];
    int kind[2];
    for (int i = 0; i < 2; ++i) {
        tie(col[i], kind[i]) = paint(S[i]);
    }
    Graph g[2];
    for (int i = 0; i < 2; ++i) {
        g[i] = gen(S[i], col[i], kind[i]);
    }

    return isomorphism_rooted(g[0], g[1], 0, 0);
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    while (true) {
        cout << (solve() ? "yes" : "no")<< '\n';
    }
}
accuracy: 1
time_ms: 150
memory_kb: 3588
final_rank: 17