Problem:
Go around the Labyrinth
Explorer Taro got a floor plan of a labyrinth.
The floor of this labyrinth is in the form of a two-dimensional grid.
Each of the cells on the floor plan corresponds to a room and is indicated whether it can be entered or not.
The labyrinth has only one entrance located at the northwest corner, which is upper left on the floor plan.
There is a treasure chest in each of the rooms at other three corners, southwest, southeast, and northeast.
To get a treasure chest, Taro must move onto the room where the treasure chest is placed.
Taro starts from the entrance room and repeats moving to one of the enterable adjacent rooms in the four directions, north, south, east, or west.
He wants to collect all the three treasure chests and come back to the entrance room.
A bad news for Taro is that, the labyrinth is quite dilapidated and even for its enterable rooms except for the entrance room, floors are so fragile that, once passed over, it will collapse and the room becomes not enterable.
Determine whether it is possible to collect all the treasure chests and return to the entrance.
Input
The input consists of at most 100 datasets, each in the following format.
N
M
c
1,1
...
c
1,
M
...
c
N
,1
...
c
N
,
M
The first line contains
N
, which is the number of rooms in the north-south direction, and
M
, which is the number of rooms in the east-west direction.
N
and
M
are integers satisfying 2 ≤
N
≤ 50 and 2 ≤
M
≤ 50.
Each of the following
N
lines contains a string of length
M
.
The
j
-th character
c
i,j
of the
i
-th string represents the state of the room (
i,j
),
i
-th from the northernmost and
j
-th from the westernmost;
the character is the period ('
.
') if the room is enterable and the number sign ('
#
') if the room is not enterable.
The entrance is located at (1,1), and the treasure chests are placed at (
N,
1), (
N,M
) and (1,
M
).
All of these four rooms are enterable.
Taro cannot go outside the given
N
×
M
rooms.
The end of the input is indicated by a line containing two zeros.
Output
For each dataset, output
YES
if it is possible to collect all the treasure chests and return to the entrance room, and otherwise, output
NO
in a single line.
Sample Input
3 3
...
.#.
...
5 5
..#..
.....
#....
.....
.....
3 8
..#.....
........
.....#..
3 5
..#..
.....
..#..
4 4
....
....
..##
..#.
0 0
Output for the Sample Input
YES
NO
YES
NO
NO

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
const int INF = 1e9;

template<typename flow>
struct max_flow {
    struct edge {
        int to;
        flow cap;
        int rev;
    };
    int V;
    vector<vector<edge> > G;
    vector<int> itr, level;
    max_flow(int V) : V(V) {G.assign(V, vector<edge>()); }

    void add_edge(int from, int to, flow cap) {
        G[from].push_back((edge){to, cap, (int)G[to].size()});
        G[to].push_back((edge) {from, 0, (int)G[from].size()-1});
    }

    void bfs(int s) {
        level.assign(V, -1);
        queue<int> q;
        level[s] = 0;
        q.push(s);
        while(!q.empty()) {
            int v = q.front();
            q.pop();
            for(auto &e : G[v]) {
                if(e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[v] + 1;
                    q.push(e.to);
                }
            }
        }
    }

    flow dfs(int v, int t, flow f) {
        if(v == t) return f;
        for(int& i = itr[v]; i < (int)G[v].size(); ++i) {
            edge &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to]) {
                flow d = dfs(e.to, t, min(f, e.cap));
                if(d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    flow run(int s, int t) {
        flow ret = 0, f;
        while(bfs(s), level[t] >= 0) {
            itr.assign(V, 0);
            while((f = dfs(s, t, INF)) > 0) ret += f;
        }
        return ret;
    }
};

int H, W;
string field[55];
int dh[4] = {1, -1, 0, 0};
int dw[4] = {0, 0, 1, -1};
max_flow<int> init() {
    max_flow<int> graph(10001);
    graph.add_edge(1*W+1, 1*W+1+5000, 1);
    graph.add_edge(H*W+1, H*W+1+5000, 1);
    graph.add_edge(H*W+W-1, H*W+W-1+5000, 1);
    graph.add_edge(1*W+W-1, 1*W+W-1+5000, 1);
    for(int h = 1; h <= H; h++) {
        for(int w = 1; w <= W; w++) {
            if(field[h][w] == '#') continue;
             graph.add_edge(h*W + w, h*W + w + 5000, 1);
             for(int k = 0; k <= 3; k++) {
                 int newh = h + dh[k];
                 int neww = w + dw[k];
                 if(newh <= 0 || newh > H || neww <= 0 || neww > W) continue;
                 if(field[newh][neww] == '#') continue;
                 graph.add_edge(h*W+w + 5000, newh*W+neww, 1);
             }
        }
    }
    return graph;
}

int TARGET = 10000;

int main() {
    while(true) {
        cin >> H >> W;
        if(H == 0 && W == 0) break;
        for(int i = 1; i <= H; i++) {
            cin >> field[i];
            field[i] = "&" + field[i];
        }
        bool clear = true;
        max_flow<int> graph = init();
        graph.add_edge(0, 1*W+1, 1);
        graph.add_edge(0, H*W+1, 1);
        graph.add_edge(1*W+W-1 + 5000, TARGET, 1);
        graph.add_edge(H*W+W-1 + 5000, TARGET, 1);
        if(graph.run(0, TARGET) < 2) clear = false;
        graph = init();
        graph.add_edge(0, 1*W+1, 1);
        graph.add_edge(0, 1*W+W-1, 1);
        graph.add_edge(H*W+1 + 5000, TARGET, 1);
        graph.add_edge(H*W+W-1 + 5000, TARGET, 1);
        if(graph.run(0, TARGET) < 2) clear = false;
        graph = init();
        graph.add_edge(0, 1*W+1, 2);
        graph.add_edge(0, H*W+W-1, 2);
        graph.add_edge(1*W+W-1 + 5000, TARGET, 2);
        graph.add_edge(H*W+1 + 5000, TARGET, 2);
        if(graph.run(0, TARGET) < 4) clear = false;
        if(clear) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 4748
final_rank: 7

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

#include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder {

struct dsu {
  public:
    dsu() : _n(0) {}
    explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        return _leader(a);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    std::vector<int> parent_or_size;

    int _leader(int a) {
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = _leader(parent_or_size[a]);
    }
};

}  // namespace atcoder

using namespace std;
using namespace atcoder; 
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define rrep(i,start,end) for (ll i = start;i >= (ll)(end);i--)
#define repn(i,end) for(ll i = 0; i <= (ll)(end); i++)
#define reps(i,start,end) for(ll i = start; i < (ll)(end); i++)
#define repsn(i,start,end) for(ll i = start; i <= (ll)(end); i++)
#define each(p,a) for(auto &p:a)
typedef vector<ll> vll;
typedef vector<pair<ll ,ll>> vpll;
typedef vector<vector<ll>> vvll;
typedef set<ll> sll;
typedef map<ll , ll> mpll;
typedef pair<ll ,ll> pll;
typedef tuple<ll , ll , ll> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (ll)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
ll lceil(ll a,ll b){if(a%b==0){return a/b;}if(a>=0){return (a/b)+1;}else{return -((-a)/b);}}
ll lfloor(ll a,ll b){if(a%b==0){return a/b;}if(a>=0){return (a/b);}else{return -((-a)/b)-1;}}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
//0indexed
inline ll topbit(ll a){assert(a != 0);return 63 - __builtin_clzll(a);}
inline ll smlbit(ll a){assert(a != 0);return __builtin_ctzll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

struct Lowlink{
  ll n;
  vector<ll> ord;
  vector<ll>low;
  vector<ll>articulation,bridge;//atriculation 関節点,bridgeは橋になる辺の番号を格納 
  vector<vector<pll>> g;
  vector<ll>found;
  vector<ll> c;//二重辺連結分解で使用
  ll m;//辺の数
 
  Lowlink(ll _n):n(_n),m(0){
    ord.resize(n,INF);
    low.resize(n);
    g.resize(n);
    found.resize(n);
  }
 
  ll add_edge(ll u, ll v){
    g[u].push_back({v,m});
    g[v].push_back({u,m});
    return m++;
  }
 
  ll dfs(ll v,ll par, ll num){
    ord[v] = num;
    low[v] = num;
    found[v] =1;
    bool isa = false; //関節点かどうか
    ll cnt = 0;//ｖが根のときに関節点かどうか判定に使用
    for(auto &p:g[v]){
      auto[to,id]  = p;
      if(to == par){continue;}
      if(found[to] != 0){
        //発見済みだったから今見ている辺は後退辺
        chmin(low[v],ord[to]);
      }else{
        //未発見
        cnt++;
        num = dfs(to,v,num+1);
        if(par != -1 && low[to] >= ord[v]){
          isa = true;
        }
        chmin(low[v],low[to]);
        if(ord[v] < low[to]){
          //子のlowが子で終わってたらbridge
          bridge.push_back(id);
        }
      }
    }
    if(par == -1  && cnt >= 2)isa = true;
    if(isa)articulation.push_back(v);//関節点だった
    return num + 1;
  }
  //構築して連結成分数を返す 
  ll build(){
    ll k = 0;
    ll cnt = 0;//シンプルに連結成分数
    rep(i,n){
      if(found[i] == 0){
        k = dfs(i,-1,k);
        cnt++;
      }
    }
    return cnt; //シンプルに連結成分数を返しておく
  }
 
  vector<vector<ll>> bc;
  vector<ll> bc_id;
  //二重頂点連結分解
  void bcc(){
    bc_id = vector<ll>(m,-1);
    vector<ll> used(n);
    auto add = [&](ll id,ll num){
      bc[num].push_back(id);
      bc_id[id] = num;
    };
    auto dfs = [&](auto dfs,ll v,ll par,ll num)->void{
      used[v] = 1;
      for(auto &[to,id]:g[v]){
        if(to == par){continue;}
        if(used[to] == 0 ){
          ll nownum = num;
          if(low[to] >= ord[v]){
            nownum = bc.size();
            bc.push_back({});//新しくグループ作る
          }
          add(id,nownum);
          dfs(dfs,to,v,nownum);
        }else if(ord[to] < ord[v]){
          add(id,num);//後退辺は同じグループ
        }
      }
    };
    rep(i,n){
      if(used[i] == 0){
        dfs(dfs,i,-1,-1);
      }
    }
  }

  

  //二重辺連結分解 build()した後
  //cに各頂点がどのグループに属するか格納される
  //グラフから橋を全て削除したときの連結成分
  ll two_edge_connect_component(){
    //~~~~~~二重辺連結分解~~~~~~~~~~~
    // 計算量 O(n+m)
    c.resize(n,-1);
    ll ccnt = 0;
    rep(i,n){
      if(c[i] == -1){
        auto dfs2 = [&](auto dfs2, ll v,ll par,ll num)->ll{
          if(par != -1 && ord[par] >= low[v]){
            c[v] = c[par];
          }else{
            c[v] = num++;
          }
          for(auto &[to,id]:g[v]){
            if(c[to] == -1){
              num = dfs2(dfs2,to,v,num);
            }
          }
          return num;
        };
        ccnt = dfs2(dfs2,i,-1,ccnt);
      }
    }
    return ccnt;
  }
};


void solve(ll n,ll m){
  vector<string > s(n);
  rep(i,n){
    cin >> s[i];
  }
  // vvll g(n *m);
  auto clc = [&](ll i,ll j){
    return i * m + j;
  };

  set<pll> kado ={{0,0},{n-1,m-1},{n-1,0},{0,m-1}};
  
  rep(I,n)rep(J,m)if(!kado.contains({I,J})){
    dsu uf(n*m);
    rep(i,n){
      rep(j,m)if(s[i][j] != '#' && (i != I or j != J)){
        rep(k,4){
          ll ny = i + _ta[k];
          ll nx = j + _yo[k];
          if(isin(ny,nx,n,m)&& s[ny][nx] != '#'&& (ny !=I or nx != J)){
            uf.merge(clc(i,j),clc(ny,nx));
          }
        }
      }
    }
    // bool ok = true;
    if(!uf.same(clc(0,0),clc(0,m-1))){
      cout <<"NO" << endl;
      return ;
    }
    if(!uf.same(clc(0,0),clc(n-1,m-1))){
      cout << "NO" << endl;
      return ;
    }
    if(!uf.same(clc(0,0),clc(n-1,0))){
      cout << "NO" << endl;
      return ;
    }
  }
  
  cout << "YES" << endl;

}
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  while(true){
    LL(n,m);
    if(n == 0 && m == 0)break;
    solve(n,m);
  }
}
accuracy: 1
time_ms: 520
memory_kb: 3712
final_rank: 14

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

#include <atcoder/all>
using namespace atcoder;

using ll = long long;
using mint = modint998244353;

bool solve() {
    int N, M;
    cin >> N >> M;
    if(N == 0) return false;
    vector<string> S(N);
    for(int i = 0; i < N; i++) {
        cin >> S[i];
    }
    if(S[0][1] == '#' || S[1][0] == '#') {
        cout << "NO" << endl;
        return true;
    }
    if(S[0][M - 2] == '#' || S[1][M - 1] == '#') {
        cout << "NO" << endl;
        return true;
    }
    if(S[N - 1][1] == '#' || S[N - 2][0] == '#') {
        cout << "NO" << endl;
        return true;
    }
    if(S[N - 1][M - 2] == '#' || S[N - 2][M - 1] == '#') {
        cout << "NO" << endl;
        return true;
    }
    if(N <= 3 && M <= 3) {
        cout << "YES" << endl;
        return true;
    }
    auto ID = [&](int i, int j) -> int {
        return i * M + j;
    };
    // cout << "non-trivial" << endl;
    vector<pair<int, int>> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    mf_graph<int> g(2 * N * M + 2);
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < M; j++) {
            if(S[i][j] == '#') continue;
            int x = ID(i, j);
            g.add_edge(2 * x, 2 * x + 1, 1);
            for(auto [di, dj] : dirs) {
                int ii = i + di, jj = j + dj;
                if(!(0 <= ii && ii < N && 0 <= jj && jj < M && S[ii][jj] == '.')) continue;
                // cout << i << " " << j << " " << ii << " " << jj << endl;
                int y = ID(ii, jj);
                g.add_edge(2 * x + 1, 2 * y, 1);
                g.add_edge(2 * y + 1, 2 * x, 1);
            }
        }
    }
    mf_graph<int> ga = g;
    mf_graph<int> gb = g;
    mf_graph<int> gc = g;
    const int SRC = 2 * N * M;
    const int DST = 2 * N * M + 1;
    {
        ga.add_edge(SRC, 2 * ID(0, 1), 1);
        ga.add_edge(SRC, 2 * ID(1, 0), 1);
        ga.add_edge(2 * ID(N - 1, M - 2) + 1, DST, 1);
        ga.add_edge(2 * ID(N - 2, M - 1) + 1, DST, 1);
        int f = ga.flow(SRC, DST);
        // vector ma(N, vector<int>(M));
        // for(auto e : ga.edges()) {
        //     int p = e.from;
        //     int q = e.to;
        //     if(p != SRC && q != DST && p % 2 == 0 && q % 2 == 1 && p + 1 == q) {
        //         int i = (p / 2) / M;
        //         int j = (p / 2) % M;
        //         ma[i][j] = e.flow;
        //     }
        // }
        // for(int i = 0; i < N; i++) {
        //     for(int j = 0; j < M; j++) {
        //         cout << ma[i][j] << " \n"[j == M - 1];
        //     }
        // }
        if(f < 2) {
            // cout << "type1" << " " << f << endl;
            cout << "NO" << endl;
            return true;
        }
    }
    {
        gb.add_edge(SRC, 2 * ID(N - 2, 0), 1);
        gb.add_edge(SRC, 2 * ID(N - 1, 1), 1);
        gb.add_edge(2 * ID(1, 0) + 1, DST, 1);
        gb.add_edge(2 * ID(N - 1, M - 2) + 1, DST, 1);
        int f = gb.flow(SRC, DST);
        if(f < 2) {
            // cout << "type2" << " " << f << endl;
            cout << "NO" << endl;
            return true;
        }
    }
    {
        gc.add_edge(SRC, 2 * ID(0, M - 2), 1);
        gc.add_edge(SRC, 2 * ID(1, M - 1), 1);
        gc.add_edge(2 * ID(0, 1) + 1, DST, 1);
        gc.add_edge(2 * ID(N - 2, M - 1)  + 1, DST, 1);
        int f = gc.flow(SRC, DST);
        if(f < 2) {
            // cout << "type3" << " " << f << endl;
            cout << "NO" << endl;
            return true;
        }
    }
    cout << "YES" << endl;
    return true;
}

int main() {
    while(solve());
}
accuracy: 1
time_ms: 20
memory_kb: 8148
final_rank: 18

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


using namespace std;
//make -f ../makefile SRC=
/*
ad hoc => WA
max flow WA:
vertex cannot be transversed more than once
edge <-> vertex OR multiple layers of grid (2 layer !)

*/


//------------------------------------------------------------------------------
bool DEBUG = false;
const int INF = 2147483647;

const int MAX_N = 50;
static bool G[MAX_N][MAX_N];

typedef pair<int,int> PA;
typedef vector<PA> PAS;
static PAS action = {{-1,0}, {0,1}, {1,0}, {0,-1}};

typedef vector<int> States;
//------------------------------------------------------------------------------
const int MAX_NN = 2*MAX_N*MAX_N + 2;
static int level[MAX_NN];
static int start[MAX_NN];

//------------------------------------------------------------------------------
struct Edge
{
    int w, f, c, j;

    bool operator<(const Edge& other) const
    {
        return f < other.f;
    }

    Edge(): w(-1), f(0), c(0), j(-1) {}
    Edge(int v2, int flow, int capacity, int reverse_edge): w(v2), f(flow), c(capacity), j(reverse_edge) {}
    void debug() const { printf("(%d, %d, %d, %d)\n", w, f, c, j); }
};

typedef vector<Edge> Edges;
typedef vector<Edges> GRAPH;

//------------------------------------------------------------------------------
void add_edge(int N, GRAPH& G, int v, int w, int c)
{
    // forward edge:
    Edge e1(w, 0, c, G[w].size());

    // backward edge:
    Edge e2(v, 0, 0, G[v].size());

    G[v].push_back( e1 );
    G[w].push_back( e2 );
}

//------------------------------------------------------------------------------
bool bfs(int NN, GRAPH& GG, int src, int dest)
{
    //--------------------------------------------------------------------------
    // setup params:
    for (int v=0; v<NN; ++v) level[v] = -1;

    queue<int> Q;
    Q.push(src);
    level[src] = 0;

    //--------------------------------------------------------------------------
    // search:
    while (!Q.empty())
    {
        int v = Q.front(); Q.pop();
        for (Edge e: GG[v])
        {
            if (level[e.w] < 0 && e.f < e.c)
            {
                level[e.w] = level[v] + 1;
                Q.push(e.w);
            }
        }
    }

    //--------------------------------------------------------------------------
    // is dest reachable from src?
    return level[dest] >= 0;
}

int send_flow(int NN, GRAPH& GG, int v, int dest, int flow)
{
    if (v == dest) return flow;
    for (; start[v]<GG[v].size(); start[v]++)
    { 
        Edge& e = GG[v][start[v]];
        if (level[e.w] == level[v] + 1 && e.f < e.c)
        {
            int min_flow = min(flow, e.c-e.f);
            int new_flow = send_flow(NN, GG, e.w, dest, min_flow);
  
            if (new_flow)
            { 
                e.f += new_flow;
                GG[e.w][e.j].f -= new_flow;
                return new_flow; 
            }
        }
    }
    return 0;
}


//------------------------------------------------------------------------------
int dinic(int NN, GRAPH& GG, int src, int dest)
{
    //if (DEBUG) {for (int v=0; v<NN; ++v) for (Edge e: GG[v]) { printf("%d -> ", v); e.debug(); }}

    //--------------------------------------------------------------------------
    // base cases:
    if (dest == src) return 0;

    //--------------------------------------------------------------------------
    // init params:
    int res = 0;

    //--------------------------------------------------------------------------
    // compute:
    while (bfs(NN, GG, src, dest))
    {
        for (int v=0; v<NN; ++v) start[v] = 0;
        while (int flow = send_flow(NN, GG, src, dest, INF)) res += flow;
    }

    //--------------------------------------------------------------------------
    // report:
    return res;
}

//------------------------------------------------------------------------------
void debug_grid(int M, int N)
{
    printf("grid:\n");
    for (int m=0; m<M; ++m) { for (int n=0; n<N; ++n) printf("%d ",G[m][n]); printf("\n"); }
    printf("\n");
}


States neighbors(int M, int N, int v)
{
    States SS;
    int m1 = v/N;
    int n1 = v%N;
    if (!G[m1][n1]) return SS;

    int m2, n2, w;
    //--------------------------------------------------------------------------
    for (PA p: action)
    {
        m2 = m1 + p.first;
        n2 = n1 + p.second;
        if (m2 < 0 || m2 >= M || n2 < 0 || n2 >= N || !G[m2][n2]) continue;
        w = m2*N + n2;
        SS.push_back( w );
    }

    //--------------------------------------------------------------------------
    return SS;
}

//------------------------------------------------------------------------------
bool ok(int M, int N)
{
    for (int m=0; m<M; ++m)
        for (int n=0; n<N; ++n)
            if (!G[m][n])
                return false;
    return true;
}

bool feasible(int M, int N)
{
    int v;
    v = 0;
    if (neighbors(M, N, v).size() < 2) return false;

    v = N-1;
    if (neighbors(M, N, v).size() < 2) return false;

    v = M*N-1;
    if (neighbors(M, N, v).size() < 2) return false;

    v = M*N-N;
    if (neighbors(M, N, v).size() < 2) return false;

    return true;
}


GRAPH setup(int M, int N)
{
    int NN = 2*M*N+2;
    int src = NN-2;

    GRAPH GG(NN);
    add_edge(NN, GG, src, 0, 2);

    for (int v=0; v<M*N; ++v)
    {
        if (!G[v/N][v%N]) continue;

        add_edge(NN, GG, M*N+v, v, 1); //<----------

        for (int w: neighbors(M, N, v))
            add_edge(NN, GG, v, w+M*N, 1);
    }

    return GG;
}

//------------------------------------------------------------------------------
bool solve(int M, int N)
{
    if (DEBUG) debug_grid(M, N);
    //--------------------------------------------------------------------------
    // base cases:
    if (M == 2 || N == 2) return ok(M, N);
    if (!feasible(M, N)) return false;
    //--------------------------------------------------------------------------
    // init:
    //--------------------------------------------------------------------------
    // compute:
    int NN = 2*M*N+2;
    int src = NN-2;

    vector<int> dests = {N-1 + M*N, M*N-1 + M*N, M*N-N + M*N};
    for (int dest: dests)
    {
        GRAPH GG = setup(M, N);
        int flow = dinic(NN, GG, src, dest);
        if (flow != 2) return false;
    }
    //--------------------------------------------------------------------------
    // report:
    return true;
}

//------------------------------------------------------------------------------
void test()
{

}

//------------------------------------------------------------------------------
int main()
{
    //test(); return 0;
    //DEBUG = true;
    //--------------------------------------------------------------------------
    int M, N, num;
    char c;
    while (true)
    {
        num = scanf("%d %d ", &M, &N);
        if (M == 0 && N == 0) break;
        for (int m=0; m<M; ++m)
            for (int n=0; n<N; ++n)
                { num = scanf("%c ", &c); if (c == '.') G[m][n] = true; else G[m][n] = false; }
        if (solve(M, N)) printf("YES\n");
        else printf("NO\n");
    }
    //--------------------------------------------------------------------------
    return 0;
}
//------------------------------------------------------------------------------
accuracy: 1
time_ms: 30
memory_kb: 3784
final_rank: 1

code_snippet: #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;
#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;
}
constexpr int INF = 1001001001;
constexpr int64_t llINF = 3000000000000000000;

#include <algorithm>
#include <vector>

namespace atcoder {

namespace internal {

template <class T>
struct simple_queue {
    std::vector<T> payload;
    int pos = 0;
    void reserve(int n) { payload.reserve(n); }
    int size() const { return int(payload.size()) - pos; }
    bool empty() const { return pos == int(payload.size()); }
    void push(const T& t) { payload.push_back(t); }
    T& front() { return payload[pos]; }
    void clear() {
        payload.clear();
        pos = 0;
    }
    void pop() { pos++; }
};

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <limits>
#include <queue>
#include <vector>

namespace atcoder {

template <class Cap>
struct mf_graph {
   public:
    mf_graph() : _n(0) {}
    mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        int from_id = int(g[from].size());
        int to_id = int(g[to].size());
        if (from == to) to_id++;
        g[from].push_back(_edge{to, to_id, cap});
        g[to].push_back(_edge{from, from_id, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for (int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& _e = g[pos[i].first][pos[i].second];
        auto& _re = g[_e.to][_e.rev];
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) { return flow(s, t, std::numeric_limits<Cap>::max()); }
    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);

        std::vector<int> level(_n), iter(_n);
        internal::simple_queue<int> que;

        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for (auto e : g[v]) {
                    if (e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if (v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for (int& i = iter[v]; i < int(g[v].size()); i++) {
                _edge& e = g[v][i];
                if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d = self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                if (d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if (res == up) break;
            }
            return res;
        };

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            while (flow < flow_limit) {
                Cap f = dfs(dfs, t, flow_limit - flow);
                if (!f) break;
                flow += f;
            }
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        internal::simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for (auto e : g[p]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

   private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

}  // namespace atcoder

void solve() {
    int n, m;
    cin >> n >> m;
    if (n == 0 && m == 0) exit(0);
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    atcoder::mf_graph<int> mf(n * m * 2 + 2);
    vector<vector<int>> id(n, vector<int>(m));
    {
        int t = 0;
        rep(i, n) rep(j, m) id[i][j] = t++;
    }
    rep(i, n) {
        rep(j, m) {
            if (s[i][j] == '#') continue;
            mf.add_edge(id[i][j], id[i][j] + n * m, 1);

            if (i + 1 < n && s[i + 1][j] == '.') mf.add_edge(id[i][j] + n * m, id[i + 1][j], 1);
            if (j + 1 < m && s[i][j + 1] == '.') mf.add_edge(id[i][j] + n * m, id[i][j + 1], 1);
            if (i && s[i - 1][j] == '.') mf.add_edge(id[i][j] + n * m, id[i - 1][j], 1);
            if (j && s[i][j - 1] == '.') mf.add_edge(id[i][j] + n * m, id[i][j - 1], 1);
        }
    }
    auto mf2 = mf;
    cout << (mf.flow(n * m, id[n - 1][m - 1], 2) == 2 && mf2.flow(id[n - 1][0] + n * m, id[0][m - 1], 2) == 2 ? "YES" : "NO") << endl;
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    /*int t;
    cin >> t;
    while (t--) */
    while (1) solve();
}
accuracy: 1
time_ms: 10
memory_kb: 4704
final_rank: 6

code_snippet: #include<iostream>
#include<vector>

#include <algorithm>
#include <cassert>
#include <limits>
#include <queue>
#include <vector>


#include <vector>

namespace atcoder {

namespace internal {

template <class T> struct simple_queue {
    std::vector<T> payload;
    int pos = 0;
    void reserve(int n) { payload.reserve(n); }
    int size() const { return int(payload.size()) - pos; }
    bool empty() const { return pos == int(payload.size()); }
    void push(const T& t) { payload.push_back(t); }
    T& front() { return payload[pos]; }
    void clear() {
        payload.clear();
        pos = 0;
    }
    void pop() { pos++; }
};

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

template <class Cap> struct mf_graph {
  public:
    mf_graph() : _n(0) {}
    explicit mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        int from_id = int(g[from].size());
        int to_id = int(g[to].size());
        if (from == to) to_id++;
        g[from].push_back(_edge{to, to_id, cap});
        g[to].push_back(_edge{from, from_id, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for (int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& _e = g[pos[i].first][pos[i].second];
        auto& _re = g[_e.to][_e.rev];
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }
    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);

        std::vector<int> level(_n), iter(_n);
        internal::simple_queue<int> que;

        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for (auto e : g[v]) {
                    if (e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if (v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for (int& i = iter[v]; i < int(g[v].size()); i++) {
                _edge& e = g[v][i];
                if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d =
                    self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                if (d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if (res == up) return res;
            }
            level[v] = _n;
            return res;
        };

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            Cap f = dfs(dfs, t, flow_limit - flow);
            if (!f) break;
            flow += f;
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        internal::simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for (auto e : g[p]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

  private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

}  // namespace atcoder

using namespace std;
const vector<pair<int,int>>D={{1,0},{-1,0},{0,1},{0,-1}};
bool solve()
{
    int H,W;
    cin>>H>>W;
    if(H==0&&W==0)return false;
    vector<string>S(H);
    for(int i=0;i<H;i++)cin>>S[i];
    const int N=H*W;
    atcoder::mf_graph<long long>G(2*N);
    G.add_edge(0,N,1);
    for(int r=0;r<H;r++)for(int c=0;c<W;c++)G.add_edge(r*W+c,r*W+c+N,1);
    for(int r=0;r<H;r++)for(int c=0;c<W;c++)if(S[r][c]=='.')
    {
        for(auto[dr,dc]:D)
        {
            int tr=r+dr,tc=c+dc;
            if(0<=tr&&tr<H&&0<=tc&&tc<W&&S[tr][tc]=='.')G.add_edge(r*W+c+N,tr*W+tc,1);
        }
    }
    auto GG=G,GGG=G;
    cout<<(G.flow(0,W-1)==2&&GG.flow(0,N-W)==2&&GGG.flow(0,N-1)==2?"YES":"NO")<<'\n';
    return true;
}
int main(){while(solve()){}}
accuracy: 1
time_ms: 20
memory_kb: 5584
final_rank: 8

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

struct dsu {
    vector<int> p, sz;
    dsu(int n) : p(n), sz(n) {
        iota(p.begin(), p.end(), 0);
    }
    int find(int x) {
        return (p[x] == x ? x : p[x] = find(p[x]));
    }
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    void merge(int x, int y) {
        x = find(x), y = find(y);
        if (sz[x] < sz[y]) swap(x, y);
        p[y] = x;
        sz[x] += sz[y];
    }
};

bool solve() {
    int N, M; cin >> N >> M;
    if (!N) return false;
    vector S(N, string());
    for (auto& s : S) cin >> s;
    vector<vector<bool>> G(N, vector(M, false));
    for (int i = 0 ; i < N ; i++) {
        for (int j = 0 ; j < M ; j++) {
            G[i][j] = S[i][j] == '.';
        }
    }
    auto valid = [&](int y, int x) -> bool {
        return 0 <= y and y < N and 0 <= x and x < M and G[y][x];
    };
    auto f = [&](int y, int x) -> int {
        return y * M + x;
    };
    array<int, 4> dy = { 1, 0, -1, 0 };
    array<int, 4> dx = { 0, 1, 0, -1 };
    for (int i = 0 ; i < N ; i++) {
        for (int j = 0 ; j < M ; j++) {
            if (not G[i][j]) continue;
            if (i == 0 and j == 0) continue;
            if (i == N - 1 and j == 0) continue;
            if (i == 0 and j == M - 1) continue;
            if (i == N - 1 and j == M - 1) continue;
            dsu uf(N * M);
            for (int y = 0 ; y < N ; y++) {
                for (int x = 0 ; x < M ; x++) {
                    if (y == i and x == j) continue;
                    if (not G[y][x]) continue;
                    for (int d = 0 ; d < 4 ; d++) {
                        int ny = y + dy[d], nx = x + dx[d];
                        if (not valid(ny, nx)) continue;
                        if (ny == i and nx == j) continue;
                        uf.merge(f(y, x), f(ny, nx));
                    }
                }
            }
            bool ok = true;
            ok &= uf.same(f(0, 0), f(N - 1, 0));
            ok &= uf.same(f(N - 1, 0), f(N - 1, M - 1));
            ok &= uf.same(f(N - 1, M - 1), f(0, M - 1));
            if (not ok) {
                // cout << i << ' ' << j << endl;
                cout << "NO" << endl;
                return true;
            }
        }
    }
    dsu uf(N * M);
    for (int y = 0 ; y < N ; y++) {
        for (int x = 0 ; x < M ; x++) {
            if (not G[y][x]) continue;
            for (int d = 0 ; d < 4 ; d++) {
                int ny = y + dy[d], nx = x + dx[d];
                if (not valid(ny, nx)) continue;
                uf.merge(f(y, x), f(ny, nx));
            }
        }
    }
    bool ok = true;
    ok &= uf.same(f(0, 0), f(N - 1, 0));
    ok &= uf.same(f(N - 1, 0), f(N - 1, M - 1));
    ok &= uf.same(f(N - 1, M - 1), f(0, M - 1));
    if (not ok) {
        // cout << i << ' ' << j << endl;
        cout << "NO" << endl;
        return true;
    }
    cout << "YES" << endl;
    return true;
}

int main() {
    while (solve()) ;
}
accuracy: 1
time_ms: 780
memory_kb: 3516
final_rank: 17

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

#include <algorithm>

#include <vector>

namespace atcoder {

namespace internal {

template <class T> struct simple_queue {
    std::vector<T> payload;
    int pos = 0;
    void reserve(int n) { payload.reserve(n); }
    int size() const { return int(payload.size()) - pos; }
    bool empty() const { return pos == int(payload.size()); }
    void push(const T& t) { payload.push_back(t); }
    T& front() { return payload[pos]; }
    void clear() {
        payload.clear();
        pos = 0;
    }
    void pop() { pos++; }
};

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <limits>
#include <queue>
#include <vector>

namespace atcoder {

template <class Cap> struct mf_graph {
  public:
    mf_graph() : _n(0) {}
    mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        int from_id = int(g[from].size());
        int to_id = int(g[to].size());
        if (from == to) to_id++;
        g[from].push_back(_edge{to, to_id, cap});
        g[to].push_back(_edge{from, from_id, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for (int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& _e = g[pos[i].first][pos[i].second];
        auto& _re = g[_e.to][_e.rev];
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }
    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);

        std::vector<int> level(_n), iter(_n);
        internal::simple_queue<int> que;

        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for (auto e : g[v]) {
                    if (e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if (v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for (int& i = iter[v]; i < int(g[v].size()); i++) {
                _edge& e = g[v][i];
                if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d =
                    self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                if (d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if (res == up) break;
            }
            return res;
        };

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            while (flow < flow_limit) {
                Cap f = dfs(dfs, t, flow_limit - flow);
                if (!f) break;
                flow += f;
            }
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        internal::simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for (auto e : g[p]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

  private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

}  // namespace atcoder

using namespace atcoder;
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
#define all(A) A.begin(),A.end()
#define rep(i, n) for (int i = 0; i < (int) (n); i++)

void solve(ll H,ll W) {
    vector<string> S(H);
    rep(h,H)cin>>S[h];
    mf_graph<ll> G(H*W*2);
    vll dx={1,-1,0,0};
    vll dy={0,0,1,-1};
    rep(h,H)rep(w,W){
        if(S[h][w]=='#')continue;
        G.add_edge(h*W+w,h*W+w+H*W,1);
        rep(d,4){
            ll nh=h+dy[d];
            ll nw=w+dx[d];
            if(nh<0||nw<0||nh>=H||nw>=W)continue;
            if(S[nh][nw]=='#')continue;
            G.add_edge(h*W+w+H*W,nh*W+nw,1);
        }
    }
    G.add_edge(0,H*W,1);
    auto G2=G,G3=G;
    ll an=min({G.flow(0,(H-1)*W),G2.flow(0,W-1),G3.flow(0,(H-1)*W+W-1)});
    cout<<(an==2?"YES":"NO")<<endl;
}

int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    ll H,W;
    while (cin >> H>>W) {
        if (H == 0)return 0;
        solve(H,W);
    }


}
accuracy: 1
time_ms: 20
memory_kb: 5812
final_rank: 10

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

struct Edge {
    int from;
    int to;
    int cap;
    int rev;
    Edge(int from, int to, int cap, int rev): from(from), to(to), cap(cap), rev(rev) {}
};

struct Flow {
    std::vector<std::vector<Edge>> graph;
    Flow(int n): graph(n) {}
    void add_edge(int from, int to, int cap) {
        int id = graph[from].size();
        int rev = graph[to].size();
        graph[from].emplace_back(from, to, cap, rev);
        graph[to].emplace_back(to, from, 0, id);
    }

    std::vector<bool> used;
    int dfs(int u, const int sink, int cur_flow) {
        if (u == sink) return cur_flow;
        used[u] = true;
        for (auto& e: graph[u]) {
            if (e.cap == 0) continue;
            if (used[e.to]) continue;
            int res = dfs(e.to, sink, std::min(cur_flow, e.cap));
            if (res != 0) {
                e.cap -= res;
                graph[e.to][e.rev].cap += res;
                return res;
            }
        }
        return 0;
    }

    int max_flow(int source, int sink) {
        int ans = 0;
        while (true) {
            used.assign(graph.size(), false);
            int res = dfs(source, sink, 1e9);
            if (res == 0) {
                break;
            }
            ans += res;
        }
        return ans;
    }
};

int solve() {
    int n, m;
    std::cin >> n >> m;
    if (n == 0) return 1;

    std::vector<std::string> board(n);
    for (int i = 0; i < n; i++) std::cin >> board[i];

    int offset = 0;
    std::vector in(n, std::vector<int>(m));
    std::vector mid(n, std::vector<int>(m));
    std::vector out(n, std::vector<int>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            in[i][j] = offset++;
            mid[i][j] = offset++;
            out[i][j] = offset++;
        }
    }
    const int source = out[0][0];
    Flow flow(offset);

    // in -> out
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            flow.add_edge(in[i][j], out[i][j], 1);
        }
    }

    const int DI[] = {0, 1, 0, -1};
    const int DJ[] = {1, 0, -1, 0};
    // out -> in
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (board[i][j] == '#') continue;
            for (int d = 0; d < 4; d++) {
                int ni = i + DI[d];
                int nj = j + DJ[d];
                if (ni < 0 || nj < 0 || ni >= n || nj >= m) continue;
                if (board[ni][nj] == '#') continue;
                flow.add_edge(out[i][j], in[ni][nj], 1);
            }
        }
    }

    Flow f1 = flow;
    Flow f2 = flow;
    Flow f3 = flow;
    int ff1 = f1.max_flow(source, in[0][m - 1]);
    int ff2 = f2.max_flow(source, in[n - 1][0]);
    int ff3 = f3.max_flow(source, in[n - 1][m - 1]);
    // std::cerr << ff1 << ' ' << ff2 << ' ' << ff3 << std::endl;
    if (ff1 == ff2 && ff2 == ff3 && ff3 == 2) {
        std::cout << "YES" << '\n';
    } else {
        std::cout << "NO" << '\n';
    }

    return 0;
}

int main() {
    while (!solve());
}
accuracy: 1
time_ms: 30
memory_kb: 6368
final_rank: 11

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

bool connected(int n, int m, vector<vector<char>> &c){
	vector<vector<bool>> dp(n, vector<bool>(m));
	dp[0][0] = true;
	vector<pair<int,int>> mada = {pair(0, 0)};
	vector<pair<int,int>> go = {pair(-1, 0), pair(1, 0), pair(0, 1), pair(0, -1)};
	while (!mada.empty()){
		int i = mada.back().first;
		int j = mada.back().second;
		mada.pop_back();
		for (auto [xx, yy]: go){
			int x = i + xx;
			int y = j + yy;
			if (0 <= x && x < n && 0 <= y && y < m){
				if (c[x][y] == '.' && !dp[x][y]){
					mada.push_back(pair(x, y));
					dp[x][y] = true;
				}
			}
		}
	}

	if (!dp[n-1][m-1]) return false;
	if (!dp[0][m-1]) return false;
	if (!dp[n-1][0]) return false;
	return true;
}

int main(){
	while(true){
		int n, m; cin >> n >> m;
		if (n == 0) break;

		vector<vector<char>> c(n, vector<char>(m));
		for (int i=0; i<n; i++){
			for (int j=0; j<m; j++){
				cin >> c[i][j];
			}
		}

		if (!connected(n, m, c)){
			cout << "NO" << endl;
			continue;
		}

		bool mode = true;
		for (int i=0; i<n; i++){
			for (int j=0; j<m; j++){
				if (i == 0 && j == 0) continue;
				if (i == n-1 && j == 0) continue;
				if (i == 0 && j == m-1) continue;
				if (i == n-1 && j == m-1) continue;
				if (c[i][j] == '.'){
					c[i][j] = '#';
					if (!connected(n, m, c)) mode = false;
					c[i][j] = '.';
				}
				if (!mode) break;
			}
			if (!mode) break;
		}


		if (mode) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
}
accuracy: 1
time_ms: 530
memory_kb: 3504
final_rank: 12

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

int ri() {
	int n;
	scanf("%d", &n);
	return n;
}
const std::vector<std::pair<int, int> > dd = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

bool solve() {
	int n = ri();
	int m = ri();
	
	if (!n && !m) return false;
	
	auto in = [&] (int i, int j) { return i >= 0 && i < n && j >= 0 && j < m; };
	
	std::string a[n];
	for (auto &i : a) std::cin >> i;
	
	std::vector<std::vector<bool> > used(n, std::vector<bool>(m));
	
	auto bfs = [&] (int sx, int sy) {
		std::vector<std::vector<bool> > reachable(n, std::vector<bool>(m));
		std::queue<std::pair<int, int> > que;
		reachable[sx][sy] = true;
		que.push({sx, sy});
		while (que.size()) {
			auto i = que.front();
			que.pop();
			
			auto go = [&] (int nx, int ny) {
				if (in(nx, ny) && a[nx][ny] == '.' && !used[nx][ny] && !reachable[nx][ny]) {
					reachable[nx][ny] = true;
					que.push({nx, ny});
				}
			};
			for (auto d : dd) go(i.first + d.first, i.second + d.second);
		}
		return reachable;
	};
	int x = 1;
	int y = 0;
	int last_dx = 1;
	int last_dy = 0;
	
	std::vector<std::pair<int, int> > route;
	auto go = [&] (int gx, int gy) {
		while (x != gx || y != gy) {
			used[x][y] = true;
			
			auto reachable = bfs(gx, gy);
			
			int dx = last_dy;
			int dy = -last_dx;
			bool ok = false;
			for (int i = 0; i < 4; i++) {
				if (in(x + dx, y + dy) && reachable[x + dx][y + dy]) { ok = true; break; }
				std::swap(dx, dy);
				dx *= -1;
			}
			if (!ok) return false;
			x += dx;
			y += dy;
			// std::cerr << x << " " << y << std::endl;
			last_dx = dx;
			last_dy = dy;
			route.push_back({x, y});
		}
		return true;
	};
	bool ok = a[1][0] == '.';
	ok = ok && go(n - 1, 0);
	ok = ok && go(n - 1, m - 1);
	ok = ok && go(0, m - 1);
	ok = ok && go(0, 0);
	puts(ok ? "YES" : "NO");
	
	return true;
}

int main() {
	while (solve());
	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 3448
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using vl = vector<ll>;
template<class T> using vc = vector<T>;
template<class T> using vvc = vector<vector<T>>;

#define eb emplace_back
#define all(x) (x).begin(), (x).end()
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define repr(i, n) for (ll i = (n)-1; i >= 0; i--)
#define repe(i, l, r) for (ll i = (l); i < (r); i++)
#define reper(i, l, r) for (ll i = (r)-1; i >= (l); i--)
#define repa(i,n) for (auto& i: n)

template<class T1, class T2> inline bool chmax(T1 &a, const T2 &b) {if (a<b) { a=b; return 1;} return 0;}
template<class T1, class T2> inline bool chmin(T1 &a, const T2 &b) {if (b<a) { a=b; return 1;} return 0;}

struct init{init(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);cerr<<fixed<<setprecision(15);}}init_;

template <typename T, typename U> ostream& operator<<(ostream&out,const pair<T, U>&a){return out<<a.first<<' '<<a.second;}
template <typename T> ostream& operator<<(ostream&out, const vector<T>&a){for(auto it=a.begin();it!= a.end();){out<<*it;if(++it!=a.end())out<<' ';}return out;}
template <typename T, size_t N> ostream& operator<<(ostream&out, const array<T, N>&a){for(auto it=a.begin();it!= a.end();){out<<*it;if(++it!=a.end())out<<' ';}return out;}
template <typename T> ostream& operator<<(ostream&out, const set<T>&a){for(auto it=a.begin();it!=a.end();){out<<*it;if(++it!=a.end())out<<' ';}return out;}
template <typename T, typename U> ostream& operator<<(ostream&out, const map<T, U>&a){for(auto it=a.begin();it!=a.end();){out<<*it;if(++it!=a.end())out<<'\n';}return out;}

#ifdef DEBUG
template <class T, class N> void verr(const vector<T>& a, const N& n) { rep(i, n) cerr << a[i] << " "; cerr << endl; }
template <class T, class N, size_t AN> void verr(const array<T, AN>& a, const N& n) { rep(i, n) cerr << a[i] << " "; cerr << endl; }
ll dbgt = 1; void err() { cerr << "passed " << dbgt++ << endl; }
template<class H, class... T> void err(H&& h,T&&... t){ cerr<< h << (sizeof...(t)?" ":"\n") << flush; if(sizeof...(t)>0) err(forward<T>(t)...); }
#else
void err(){}
template <class H, class... T>
void err(H &&h, T &&...t) {}
template <class H, class... T>
void verr(H &&h, T &&...t) {}
#endif

const ll INF = 4e18;
const ld EPS = 1e-11;
const ld PI = acos(-1.0L);
// const ll MOD = 1e9 + 7;
const ll MOD = 998244353;
//--------------------------------------------------------------------------------//
array<int, 4> di = {0, 1, 0, -1}, dj = {1, 0, -1, 0};

struct UnionFind {
private:
    vector<int> par;
    vector<int> count;
    vector<int> rank;
public:
    UnionFind(int N) {
        count.assign(N, 1);
        rank.assign(N, 0);
        par.assign(N, 0);
        rep(i, N) par[i] = i;
    }

    int root(int x) {
        if (par[x] == x)
            return x;
        else {
            par[x] = root(par[x]);
            return par[x];
        }
    }

    void unite(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) return;
        if (rank[x] < rank[y])
            swap(x, y);
        else if (rank[x] == rank[y])
            rank[y]++;
        par[y] = x;
        count[x] += count[y];
        return;
    }

    int size(int x) {
        return count[root(x)];
    }

    bool issame(int x, int y) {
        return root(x) == root(y);
    }
};
using UF = struct UnionFind;


void solve(int H, int W){
    vc<string> C(H);
    rep(i, H) cin >> C[i];
    vvc<int> used(H, vc<int>(W));
    rep(i, H) rep(j, W) {
        if (C[i][j] == '#') used[i][j] = true;
    }

    queue<pair<int, int>> q;
    auto padding1 = [&]() -> void {
        queue<pair<int, int>> tmpq;
        rep(i, H) rep(j, W) tmpq.emplace(i, j);
        while (!tmpq.empty()) {
            auto [i, j] = tmpq.front();
            tmpq.pop();
            int can = 0, li, lj;
            rep(d, 4) {
                int ti = i + di[d], tj = j + dj[d];
                if (ti < 0 or ti >= H or tj < 0 or tj >= W) continue;
                if (used[ti][tj]) continue;
                can++;
                li = ti, lj = tj;
            }
            if (can == 0) used[i][j] = true;
            if (can == 1) {
                used[i][j] = true;
                tmpq.emplace(li, lj);
            }
        }
    };

    padding1();

    auto cango = [&](int i, int j) -> bool {
        if (i < 0 or i >= H or j < 0 or j >= W) return false;
        if (used[i][j]) return false;
        return true;
    };
    rep(i, H) rep(j, W) {
        int can = 0;
        if (used[i][j]) continue;
        rep(d, 4) {
            int ti = i + di[d], tj = j + dj[d];
            if (!cango(ti, tj)) continue;
            can++;
        }
        if (can == 2) q.emplace(i, j);
    }
    rep(i, H) rep(j, W) {
        int can = 0;
        if (used[i][j]) continue;
        rep(d, 4) {
            int ti = i + di[d], tj = j + dj[d];
            if (!cango(ti, tj)) continue;
            can++;
        }
        if (can == 3) q.emplace(i, j);
    }
    rep(i, H) rep(j, W) {
        int can = 0;
        if (used[i][j]) continue;
        rep(d, 4) {
            int ti = i + di[d], tj = j + dj[d];
            if (!cango(ti, tj)) continue;
            can++;
        }
        if (can == 4) q.emplace(i, j);
    }
    while(!q.empty()) {
        auto [ci, cj] = q.front();
        q.pop();
        if (used[ci][cj]) continue;
        UF tuf(H * W);
        rep(i, H) rep(j, W) {
            if (i == ci and j == cj) continue;
            if (used[i][j]) continue;
            rep(d, 4) {
                int ti = i + di[d], tj = j + dj[d];
                if (ti == ci and tj == cj) continue;
                if (!cango(ti, tj)) continue;
                tuf.unite(i * W + j, ti * W + tj);
            }
        }
        bool closed = false;
        vc<pair<int, int>> ads;
        rep(d, 4) {
            int ti = ci + di[d], tj = cj + dj[d];
            if (!cango(ti, tj)) continue;
            ads.eb(ti, tj);
        }
        if (ads.size() <= 1) continue;
        set<int> st;
        for (auto [i, j] : ads) {
            st.emplace(tuf.root(i * W + j));
        }
        if (st.size() != 2) continue;
        int cli, clj;
        for (auto [i, j] : ads) {
            int id = i * W + j;
            if (tuf.issame(id, 0) or tuf.issame(id, H * W - 1) or tuf.issame(id, (H - 1) * W) or tuf.issame(id, W - 1))
                continue;
            closed = true;
            cli = i, clj = j;
        }
        if (closed) {
            // err("closed", ci, cj);
            // used[ci][cj] = true;
            rep(i, H) rep(j, W) {
                if (tuf.issame(cli * W + clj, i * W + j)) used[i][j] = true;
            }
            padding1();
            // rep(i, H) {
            //     cerr << setfill('0') << right << setw(2) << i << setfill(' ') << " ";
            //     cerr << C[i] << " ";
            //     rep(j, W) cerr << (used[i][j] ? '#' : '.');
            //     cerr << endl;
            // }
        }
    }

    padding1();

    UF uf(H * W);
    rep(i, H) rep(j, W) {
        if (used[i][j]) continue;
        rep(d, 2) {
            int ti = i + di[d], tj = j + dj[d];
            if (ti >= H or tj >= W or used[ti][tj]) continue;
            uf.unite(i * W + j, ti * W + tj);
        }
    }

    if (used[0][0] or used[0][W - 1] or used[H - 1][0] or used[H - 1][W - 1]) {
        cout << "NO" << endl;
        return;
    }

    if(!(uf.issame(0, W - 1) and uf.issame(0, (H - 1) * W) and uf.issame(0, H * W - 1))) {
        cout << "NO" << endl;
        return;
    }

    // rep(i, H) {
    //     cerr << setfill('0') << right << setw(2) << i << setfill(' ') << " ";
    //     cerr << C[i] << " ";
    //     rep(j, W) cerr << (used[i][j] ? '#' : '.');
    //     cerr << endl;
    // }

    vvc<int> arrived(H, vc<int>(W));
    int ci = 0, cj = 0, cd = 0;
    do {
        // err(ci, cj);
        int ld = (cd + 3) % 4;
        int li = ci + di[ld], lj = cj + dj[ld];
        if(cango(li, lj)) {
            ci = li, cj = lj, cd = ld;
            arrived[ci][cj] = true, used[ci][cj] = true;
            continue;
        }
        int fd = cd;
        int fi = ci + di[fd], fj = cj + dj[fd];
        if(cango(fi, fj)) {
            ci = fi, cj = fj, cd = fd;
            arrived[ci][cj] = true, used[ci][cj] = true;
            continue;
        }

        int rd = (cd + 1) % 4;
        int ri = ci + di[rd], rj = cj + dj[rd];
        if(cango(ri, rj)) {
            ci = ri, cj = rj, cd = rd;
            arrived[ci][cj] = true, used[ci][cj] = true;
            continue;
        }

        cout << "NO" << endl;
        return;
    } while (!(ci == 0 and cj == 0));

    if(arrived[0][0] and arrived[0][W - 1] and arrived[H - 1][0] and arrived[H - 1][W - 1]) {
        cout << "YES" << endl;
    }else{
        cout << "NO" << endl;
    }
}

int main() {
    while(true){
        int H, W;
        cin >> H >> W;
        if (H == 0) break;
        solve(H, W);
    }
}
accuracy: 1
time_ms: 760
memory_kb: 3512
final_rank: 16

code_snippet: #pragma GCC ta g("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 510000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-9;
//const int mod = 1e9 + 7;
const int mod = 998244353;

struct Dinic{
	struct edge{
		ll to, cap, rev;
	};
	vector<vector<edge>> G;
	vector<int> level, itr;
	ll n;
	const ll INF = 1<<30;
 
	Dinic(ll n) : n(n){
		G.resize(n);
		level.resize(n);
		itr.resize(n);
	}
 
	void add_edge(ll from, ll to, ll cap){
		G[from].push_back({to,cap,(ll)G[to].size()});
		G[to].push_back({from,0,(ll)G[from].size()-1});
	}
 
	void bfs(int s){
		fill(level.begin(), level.end(), -1);
		queue<int> q;
		level[s] = 0;
		q.push(s);
		while(!q.empty()){
			int u = q.front(); q.pop();
			for(auto &e : G[u]){
				if(e.cap > 0 && level[e.to] < 0){
					level[e.to] = level[u] + 1;
					q.push(e.to);
				}
			}
		}
	}

	ll dfs(int u, int t, ll f){
		if(u == t) return f;
		for(int &i = itr[u]; i < G[u].size(); i++){
			edge &e = G[u][i];
			if(e.cap > 0 && level[u] < level[e.to]){
				ll d = dfs(e.to, t, min(f, e.cap));
				if(d > 0){
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}
 
	ll max_flow(ll s, ll t){
		ll flow = 0;
		while(1){
			bfs(s);
			if(level[t] < 0) return flow;
			fill(itr.begin(), itr.end(), 0);
			ll f;
			while((f = dfs(s, t, INF)) > 0){
				flow += f;
			}
		}
	}
};

bool in(ll y, ll x, ll h, ll w){
	return 0 <= y && y < h && 0 <= x && x < w;
}

int main(){
	while(1){
		int n,m; cin >> n >> m;
		if(!n) break; 
		vs s(n); rep(i,n) cin >> s[i];
		Dinic a(n*m*2),b(n*m*2);
		int sa = 0, sb = (n-1)*m, ta = n*m*2-1, tb = m-1+n*m;
		rep(i,n) rep(j,m){
			if(s[i][j] == '#') continue;
			rep(k,4){
				int ny = i + dy[k];
				int nx = j + dx[k];
				if(!in(ny,nx,n,m) || s[ny][nx] == '#') continue;
				a.add_edge(i*m+j+n*m,ny*m+nx,1);
				b.add_edge(i*m+j+n*m,ny*m+nx,1);
			}
			int u = i*m+j, v = i*m+j+n*m;
			if(i==0&&j==0||i==0&&j==m-1||i==n-1&&j==0||i==n-1&&j==m-1){
				a.add_edge(u,v,2);
				b.add_edge(u,v,2);
			}else{
				a.add_edge(u,v,1);
				b.add_edge(u,v,1);
			}
		}
		if(a.max_flow(sa,ta) >= 2 && b.max_flow(sb,tb) >= 2){
			cout << "YES\n";
		}else{
			cout << "NO\n";
		}
	}
}
accuracy: 1
time_ms: 20
memory_kb: 5588
final_rank: 9

code_snippet: #include <iostream>
#include <algorithm>
#include <utility>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <map>
#include <math.h>
#include <string.h>
#include <iomanip>
#include <numeric>
#include <cstdlib>
#include <cstdint>
#include <cmath>
#include <functional>
#include <limits>
#include <cassert>
#include <bitset>
#include <chrono>
#include <random>
#include <memory>
 
/* macro */
 
#define rep(i, a, n) for (int i = (int)(a); i < (int)(n); i++)
#define rrep(i, a, n) for (int i = ((int)(n-1)); i >= (int)(a); i--)
#define Rep(i, a, n) for (i64 i = (i64)(a); i< (i64)(n); i++)
#define RRep(i, a, n) for (i64 i = ((i64)(n-i64(1))); i>=(i64)(a); i--)
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define Bit(n) (1LL<<(n))
 
/* macro end */
 
/* template */
 
namespace ebi {
 
#ifdef LOCAL
#define debug(...)                                                    \
    std::cerr << "LINE: " << __LINE__ << "  [" << #__VA_ARGS__ << "]:", \
        debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif
 
void debug_out() { std::cerr << std::endl; }
 
template <typename Head, typename... Tail>
void debug_out(Head h, Tail... t) {
    std::cerr << " " << h;
    if (sizeof...(t) > 0) std::cout << " :";
    debug_out(t...);
}
 
template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, std::pair<T1, T2> pa) {
    return os << pa.first << " " << pa.second;
}
 
template <typename T>
std::ostream& operator<<(std::ostream& os, std::vector<T> vec) {
    for (std::size_t i = 0; i < vec.size(); i++) os << vec[i] << (i + 1 == vec.size() ? "" : " ");
    return os;
}
 
using size_t = std::size_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
using ld = long double;
 
template<class T> void fill(std::vector<T> &v) { for(T &e: v) std::cin >> e; }
 
template <class T>
inline bool chmin(T &a, T b) {
    if (a > b){
        a = b;
        return true;
    }
    return false;
}
 
template <class T>
inline bool chmax(T &a, T b) {
    if (a < b){
        a = b;
        return true;
    }
    return false;
}
 
template <class T>
T gcd(T a, T b){
    if( b==0 ) return a;
    else return gcd(b, a%b);
}
 
template <class T>
T lcm(T a, T b) {
    a /= gcd(a, b);
    return a*b;
}
 
template<class T>
T Pow(T x, i64 n) {
    T res = 1;
    while(n>0){
        if(n&1) res = res *x;
        x = x*x;
        n>>=1;
    }
    return res;
}
 
template<class T>
T scan() {
    T val;
    std::cin >> val;
    return val;
}
 
constexpr i64 LNF = std::numeric_limits<i64>::max()/4;
 
constexpr int INF = std::numeric_limits<int>::max();
 
const std::vector<int> dy = {1,0,-1,0,1,1,-1,-1};
const std::vector<int> dx = {0,1,0,-1,1,-1,1,-1};
 
}
 
/* template end */

namespace ebi {

void main_() {
    int n,m;
    while(std::cin >> n >> m, !(n == 0 && m == 0)) {
        std::vector<std::string> c(n);
        rep(i,0,n) {
            std::cin >> c[i];
        }
        std::vector seen(n, std::vector<int>(m, -1));
        int by = -1, bx = -1;
        auto dfs = [&](auto &&self, int y, int x) -> void {
            seen[y][x] = 1;
            rep(i,0,4) {
                int ny = y + dy[i];
                int nx = x + dx[i];
                if(0 <= ny && ny < n && 0 <= nx && nx < m && (!(ny == by && nx == bx)) && seen[ny][nx] < 0 && c[ny][nx] != '#') {
                    self(self, ny, nx);
                }
            }
        };
        int flag = true;
        rep(i,0,n) {
            rep(j,0,m) {
                by = i;
                bx = j;
                if((by == 0 && bx == 0) || (by == 0 && bx == m-1) || (by == n-1 && bx == m-1) || (by == n-1 && bx == 0)) {
                    continue;
                }
                seen = std::vector(n, std::vector<int>(m, -1));
                dfs(dfs, 0, 0);
                if(seen[0][0] > 0 && seen[0][m-1] > 0 && seen[n-1][0] > 0 && seen[n-1][m-1] > 0) {
                    flag &= true;
                }
                else {
                    flag = false;
                }
            }
        }
        if(flag) {
            std::cout << "YES\n";
        } 
        else {
            std::cout << "NO\n";
        }
    }
}

}
 
int main() {
    std::cout << std::fixed << std::setprecision(15);
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
    int t = 1;
    // std::cin >> t;
    while(t--) {
        ebi::main_();
    }
    return 0;
}
accuracy: 1
time_ms: 830
memory_kb: 3564
final_rank: 19

code_snippet: //#pragma once
#define _CRT_SECURE_NO_WARNINGS


#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <queue>
#include <algorithm>
#include <sstream>
#include <vector>
#include <math.h>
#include <set>
#include <map>
#include <unordered_map>
#include <numeric>
#include <bitset>
#include <iomanip>
#include <cctype>
#include <cstdlib>      // srand,rand
#include <random>
#include <functional>
#include <list>
#include <stack>




using namespace std;
#define ll long long
#define ll128 long long
#define lp(i,n) for(ll i=0;i<n;i++)

#define modd 1000000007
#define mod2 998244353
const double EPS = 1e-34;
const double PI = acos(-1);

#define INF 8223372036854775807ll
#define ALL(a)  (a).begin(),(a).end()


typedef pair<long long, long long> pl;
typedef pair<long long, pl> lpl;
typedef pair<long double, long double> pd;
typedef pair<ll, string> pls;
typedef pair<string, ll> psl;



typedef string::const_iterator State;
class ParseError {};



/*
class SegmentTree {



private:

	ll cont_num = 2;
	pd initial_v;
	vector<pd> dat;


public:


	SegmentTree() {};


	void init(ll size, double initial_value_first, double initial_value_second) {

		cont_num = 2;
		initial_v.first = initial_value_first;
		initial_v.second = initial_value_second;

		while (cont_num < size) {
			cont_num *= 2;
		}

		dat.resize(2 * cont_num);//サイズ設定

		for (int i = 0; i < 2 * cont_num; i++)dat[i] = initial_v;//初期化



	}


	void Update(ll position, double value_f, double value_s) {



		ll k = cont_num + position;

		dat[k].first = value_f;
		dat[k].second = value_s;

		while (k > 1) {
			k /= 2;
			dat[k].first = dat[k * 2 + 1].first * dat[k * 2].first;
			dat[k].second = dat[k * 2 + 1].first * dat[k * 2].second + dat[k * 2 + 1].second;


		}


	}

	/*
	ll query_proces(ll a, ll b, ll k, ll l, ll r) {

		if (r <= a || b <= l)return initial_v;

		if (a <= l && r <= b)return dat[k];
		else {
			ll vl = query_proces(a, b, k * 2, l, (l + r) / 2);
			ll vr = query_proces(a, b, k * 2 + 1, (l + r) / 2, r);
			return min(vl, vr);
		}

	}


	ll query(ll left, ll right) {
		return query_proces(left, right, 1, 0, cont_num);
	}
	*/
	/*
		double query() {
			return dat[1].first + dat[1].second;
		}

	};*/


template <typename T>
class Zip {
	vector<T> d;
	bool flag;
	void init() {
		sort(d.begin(), d.end());
		d.erase(unique(d.begin(), d.end()), d.end());
		flag = false;
	}
public:
	Zip() {
		flag = false;
	}
	void add(T x) {
		d.push_back(x);
		flag = true;
	}
	ll getNum(T x) {
		if (flag) init();
		return lower_bound(d.begin(), d.end(), x) - d.begin();
	}

	T getVal(ll num) {
		return d[num];
	}

	ll size() {
		if (flag) init();
		return (ll)d.size();
	}
};




typedef struct ST
{
	ll first;
	ll second;
	ll cost;

	bool operator<(const ST& another) const
	{
		return cost < another.cost;//比較
	};

	bool operator>(const ST& another) const
	{
		return cost > another.cost;//比較
	};

}ST;
//queue<ST> qst;
priority_queue<ST, vector<ST>, greater<ST> > qst;



/*vector <ST> vst;
ST st[200005];
ST bufst;
bitset<5000> bits;*/


long long modinv(long long aa, long long mm) {
	long long bb = mm, uu = 1, vv = 0;
	while (bb) {
		long long tt = aa / bb;
		aa -= tt * bb; swap(aa, bb);
		uu -= tt * vv; swap(uu, vv);
	}
	uu %= mm;
	if (uu < 0) uu += mm;
	return uu;
}





ll zettai(ll aa) {

	if (aa < 0) {
		aa *= -1;
	}
	return aa;

}

float zettai(float aa) {

	if (aa < 0) {
		aa *= -1;
	}
	return aa;

}

double zettai(double aa) {

	if (aa < 0) {
		aa *= -1;
	}
	return aa;

}


/*
class UnionFind
{

public:


	vector <ll>pairent;
	vector <ll>depth;
	vector <ll>size;


	UnionFind(ll Amount) : pairent(Amount, 1), depth(Amount, 1), size(Amount, 1) {

		for (ll i = 0; i < Amount; i++) {
			pairent[i] = i;
		}


	}


	ll FindPairent(ll x) {
		if (pairent[x] == x)return x;
		else return pairent[x] = FindPairent(pairent[x]);

	}


	ll Merge(ll x, ll y) {
		x = FindPairent(x);
		y = FindPairent(y);

		if (x != y) {
			if (depth[x] > depth[y]) {
				pairent[y] = pairent[x];
				return size[x] += size[y];
			}
			else {
				pairent[x] = pairent[y];
				if (depth[x] == depth[y]) {
					depth[y] ++;
				}

				return size[y] += size[x];
			}

		}
		else {
			return -1;
		}



	}



	bool IsSame(ll x, ll y) {
		if (FindPairent(x) == FindPairent(y))return true;
		else return false;
	}


	ll GetSize(ll x) {
		x = FindPairent(x);
		return size[x];
	}


};
*/



template <typename T>
class RollingHash {

private:
	vector<T> all_array;
	vector<T> sub_array;
	vector<bool> match_flag;
	vector<ll128> ruijou;
	ll match_count = 0;
	vector<ll>match_place;

public:

	void Clear() {
		all_array.clear();
		sub_array.clear();
		match_flag.clear();
		match_place.clear();
	}

	RollingHash() {
		Clear();
	}

	void AddAllArray(T factor) {
		all_array.push_back(factor);
	}

	void AddSubArray(T factor) {
		sub_array.push_back(factor);
	}

	void Calculate_Ruijou(ll128 tei, ll max_num, ll128 mod) {
		ruijou.clear();
		ruijou.push_back(1);
		if (max_num > 0) {
			while (ruijou.size() < max_num + 1) {
				ruijou.push_back(ruijou.back() * tei % mod);
			}
		}

	}

	ll128 GetSubHash(ll128 b, ll128 mod) {
		ll128 ans = 0;
		Calculate_Ruijou(b, sub_array.size(), mod);
		for (ll i = 0; i < sub_array.size(); i++) {
			ans += (sub_array[i] % mod) * ruijou[sub_array.size() - 1 - i] % mod;
			ans %= mod;
		}

		return ans;
	}

	ll128 GetAllHashInit(ll128 b, ll128 mod) {
		ll128 ans = 0;
		for (ll i = 0; i < sub_array.size(); i++) {
			ans += (all_array[i] % mod) * ruijou[sub_array.size() - 1 - i] % mod;
			ans %= mod;
		}

		return ans;
	}

	void CheckMatchFlag() {
		match_place.clear();
		match_count = 0;
		for (ll i = 0; i < match_flag.size(); i++) {
			if (match_flag[i] == true) {
				match_count++;
				match_place.push_back(i);
			}
		}
	}

	void Rolling(ll128 b, ll128 mod) {
		ll128 sub_hash = GetSubHash(b, mod);
		ll128 all_hash = GetAllHashInit(b, mod);

		if (sub_hash != all_hash) {
			match_flag[0] = false;
		}

		for (ll i = 1; i < match_flag.size(); i++) {
			all_hash = (all_hash * b % mod - all_array[i - 1] % mod * ruijou[sub_array.size()] % mod + all_array[i + sub_array.size() - 1] % mod) % mod;
			while (all_hash < 0)all_hash += mod;
			all_hash %= mod;
			if (all_hash != sub_hash)match_flag[i] = false;
		}
	}

	void Match() {
		ll128 b = 3;
		//ll128 mod = 999999999999999989;
		ll128 mod = 1000000007;
		ll128 sub_hash = GetSubHash(b, mod);

		if (sub_array.size() <= all_array.size()) {

			while (match_flag.size() < all_array.size()) {
				match_flag.push_back(true);
			}

			while (match_flag.size() > all_array.size() - sub_array.size() + 1) {
				match_flag.pop_back();
			}


			Rolling(b, mod);

			b = 5;
			mod = mod2;

			Rolling(b, mod);

			b = 7;
			mod = modd;

			Rolling(b, mod);

			b = mod2;
			mod = modd;

			Rolling(b, mod);

			CheckMatchFlag();

		}



	}

	ll GetMatchCount() {
		return match_count;
	}

	ll GetMatchPlace(ll num) {
		if (num >= match_place.size())return -1;
		else return match_place[num];
	}

};



class UnionFind
{

public:

	vector <ll>pairent;
	vector <ll>depth;
	vector <ll>size;

	UnionFind(ll Amount) : pairent(Amount, 1), depth(Amount, 1), size(Amount, 1) {

		for (ll i = 0; i < Amount; i++) {
			pairent[i] = i;
		}
	}


	ll FindPairent(ll x) {
		if (pairent[x] == x)return x;
		else return pairent[x] = FindPairent(pairent[x]);
	}


	ll Merge(ll x, ll y) {
		x = FindPairent(x);
		y = FindPairent(y);

		if (x != y) {
			if (depth[x] > depth[y]) {
				pairent[y] = pairent[x];
				return size[x] += size[y];
			}
			else {
				pairent[x] = pairent[y];
				if (depth[x] == depth[y]) {
					depth[y] ++;
				}
				return size[y] += size[x];
			}
		}
		else {
			return -1;
		}
	}



	bool IsSame(ll x, ll y) {
		if (FindPairent(x) == FindPairent(y))return true;
		else return false;
	}


	ll GetSize(ll x) {
		x = FindPairent(x);
		return size[x];
	}


};




struct Edge
{
	ll a, b, cost;


	bool operator<(const Edge& other) const {
		return cost < other.cost;
	}
};

struct Graph
{
	ll n;  // 頂点数
	vector<Edge> es;  // 辺集合
};

class Kruskal {

	Graph origin_G;
	Graph MST;
	ll total_cost = 0;

public:

	void Solve() {
		UnionFind uf = UnionFind(MST.n);
		for (ll i = 0; i < origin_G.es.size(); i++) {
			ll a = origin_G.es[i].a;
			ll b = origin_G.es[i].b;
			ll cost = origin_G.es[i].cost;

			if (!uf.IsSame(a, b)) {
				uf.Merge(a, b);
				MST.es.push_back(origin_G.es[i]);
				total_cost += cost;
			}
		}
	}

	Kruskal(Graph graph) {
		origin_G = graph;
		MST = graph;
		MST.es.clear();
		sort(origin_G.es.begin(), origin_G.es.end());
	}

	ll GetMinCost() {
		return total_cost;
	}

};


ll RepeatSquaring(ll N, ll P, ll M) {
	if (P == 0) return 1;
	if (P % 2 == 0) {
		ll t = RepeatSquaring(N, P / 2, M) % M;
		return t * t % M;
	}
	return N * RepeatSquaring(N, P - 1, M) % M;
}

/*
ll KurikaesiNijou(ll a, ll b, ll P) {

	if (b == 0)return 1;
	if (b % 2 == 0) {
		ll c=KurikaesiNijou(a,b/2,P)%P;
		return c * c %P;
	}
	else {
		ll c = KurikaesiNijou(a, b/2, P) % P;
		return a * c * c % P;
	}

}*/




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

ll Min(ll a, ll b) {
	if (a < b)return a;
	else return b;
}

ll Max(ll a, ll b) {
	if (a > b)return a;
	else return b;
}

ll Sum(ll a, ll b) {
	return a + b;
}

ll Add(ll a, ll b) {
	return a + b;
}

template <typename T>
class SegmentTree {
	ll n;
	vector<T> node;
	function<T(T, T)> fun, fun2;
	bool customChange;
	T outValue, initValue;
public:
	void init(ll num, function<T(T, T)> resultFunction, T init, T out, function<T(T, T)> changeFunction = NULL) {
		// changeFunction: (input, beforevalue) => newvalue
		fun = resultFunction;
		fun2 = changeFunction;
		customChange = changeFunction != NULL;
		n = 1;
		while (n < num) n *= 2;
		node.resize(2 * n - 1);
		fill(node.begin(), node.end(), init);
		outValue = out;
		initValue = init;
	}
	void valueChange(ll num, T value) {
		num += n - 1;
		if (customChange) node[num] = fun2(value, node[num]);
		else node[num] = value;
		while (num > 0) num = (num - 1) / 2, node[num] = fun(node[num * 2 + 1], node[num * 2 + 2]);
	}
	T rangeQuery(ll a, ll b, ll l = 0, ll r = -1, ll k = 0) { // [a, b)
		if (r == -1) r = n;
		if (a <= l && r <= b) return node[k];
		if (b <= l || r <= a) return outValue;
		ll mid = (l + r) / 2;
		return fun(rangeQuery(a, b, l, mid, 2 * k + 1), rangeQuery(a, b, mid, r, 2 * k + 2));
	}
};


ll extgcd(ll a, ll b, ll& x, ll& y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	ll gcd = extgcd(b, a % b, x, y);
	ll oldX = x;
	x = y;
	y = oldX - a / b * y;
	return gcd;
}


class Combination {

	vector<ll> factorial;
	vector<ll> factorial_inv;
	ll mod;
	ll max_n;


public:
	void Init(ll init_max_n, ll init_mod) {
		max_n = init_max_n;
		mod = init_mod;
		factorial.resize(max_n + 1);
		factorial[0] = 1;
		for (ll i = 1; i < factorial.size(); i++) {
			factorial[i] = factorial[i - 1] * i;
			factorial[i] %= mod;
		}

		factorial_inv.resize(max_n + 1);
		factorial_inv[0] = 1;
		for (ll i = 1; i < factorial_inv.size(); i++) {
			factorial_inv[i] = factorial_inv[i - 1] * modinv(i, mod);
			factorial_inv[i] %= mod;
		}
	}



	ll GetComb(ll n, ll k) {
		if (n < k)return 0;
		if (k == 0)return 1;

		ll comb = factorial[n];
		comb *= factorial_inv[k];
		comb %= mod;
		comb *= factorial_inv[n - k];
		comb %= mod;
		return comb;
	}

	ll GetH(ll n, ll k) {//n+k-1<=max_N
		ll comb = factorial[n + k - 1];
		comb *= factorial_inv[n];
		comb %= mod;
		comb *= factorial_inv[k - 1];
		comb %= mod;
		return comb;
	}

};



class Tree {

	ll node_N;
	vector<ll> node;
	vector<vector<pl>> pass;
	ll diameter = -1;
	vector<ll> dist_Diamieter[2];

	pl maxDist_Num;

public:


	void Init(ll node_Num) {
		node_N = node_Num;
		node.resize(node_N + 1);
		pass.resize(node_N + 1);

		dist_Diamieter[0].resize(node_N + 1);
		lp(i, node_N + 1)dist_Diamieter[0][i] = -1;
		dist_Diamieter[1].resize(node_N + 1);
		lp(i, node_N + 1)dist_Diamieter[1][i] = -1;
	}

	void AddEdge(ll a, ll b, ll dist) {
		pl bufpl;
		bufpl.first = b;
		bufpl.second = dist;
		pass[a].push_back(bufpl);
		bufpl.first = a;
		pass[b].push_back(bufpl);
	}


	void DFS(ll step, ll now, ll dist) {

		dist_Diamieter[step][now] = dist;
		if (dist_Diamieter[step][now] > maxDist_Num.first) {
			maxDist_Num.first = dist_Diamieter[step][now];
			maxDist_Num.second = now;
		}

		for (ll i = 0; i < pass[now].size(); i++) {
			ll next_node = pass[now][i].first;
			if (dist_Diamieter[step][next_node] == -1) {
				DFS(step, next_node, dist + pass[now][i].second);
			}
		}
	}

	ll GetDiameter(ll min_node_num) {
		if (diameter >= 0)return diameter;
		else {
			maxDist_Num.first = -1;
			maxDist_Num.second = -1;
			DFS(0, min_node_num, 0ll);
			ll step2_start = maxDist_Num.second;

			maxDist_Num.first = -1;
			maxDist_Num.second = -1;
			DFS(1, step2_start, 0ll);

			diameter = maxDist_Num.first;
			return diameter;
		}
	}

	ll GetDistFromMinNode(ll num) {
		return dist_Diamieter[0][num];
	}

};




struct LDE {
	ll a, b, c, x, y;
	ll m = 0;
	bool check = true;//解が存在するか

	//初期化
	LDE(ll a_, ll b_, ll c_) : a(a_), b(b_), c(c_) {
		ll g = GCD(a, b);
		if (c % g != 0) {
			check = false;
		}
		else {
			//ax+by=gの特殊解を求める
			extgcd(abs(a), abs(b), x, y);
			if (a < 0)x = -x;
			if (b < 0)y = -y;
			//ax+by=cの特殊解を求める(オーバフローに注意！)
			x *= c / g; y *= c / g;
			//一般解を求めるために割る
			a /= g; b /= g;
		}
	}

	//拡張ユークリッドの互除法
	//返り値:aとbの最大公約数
	ll extgcd(ll a, ll b, ll& x0, ll& y0) {
		if (b == 0) {
			x0 = 1;
			y0 = 0;
			return a;
		}
		ll d = extgcd(b, a % b, y0, x0);
		y0 -= a / b * x0;
		return d;
	}

	//パラメータmの更新(書き換え)
	void m_update(ll m_) {
		x += (m_ - m) * b;
		y -= (m_ - m) * a;
		m = m_;
	}
};


/*
template< typename Monoid >
struct SegmentTreee {
	using F = function< Monoid(Monoid, Monoid) >;

	int sz;
	vector< Monoid > seg;

	const F f;
	const Monoid M1;

	SegmentTreee(int n, const F f, const Monoid& M1) : f(f), M1(M1) {
		sz = 1;
		while (sz < n) sz <<= 1;
		seg.assign(2 * sz, M1);
	}

	void set(int k, const Monoid& x) {
		seg[k + sz] = x;
	}

	void build() {
		for (int k = sz - 1; k > 0; k--) {
			seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
		}
	}

	void update(int k, const Monoid& x) {
		k += sz;
		seg[k] = x;
		while (k >>= 1) {
			seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
		}
	}

	Monoid query(int a, int b) {
		Monoid L = M1, R = M1;
		for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
			if (a & 1) L = f(L, seg[a++]);
			if (b & 1) R = f(seg[--b], R);
		}
		return f(L, R);
	}

	Monoid operator[](const int& k) const {
		return seg[k + sz];
	}

	template< typename C >
	int find_subtree(int a, const C& check, Monoid& M, bool type) {
		while (a < sz) {
			Monoid nxt = type ? f(seg[2 * a + type], M) : f(M, seg[2 * a + type]);
			if (check(nxt)) a = 2 * a + type;
			else M = nxt, a = 2 * a + 1 - type;
		}
		return a - sz;
	}


	template< typename C >
	int find_first(int a, const C& check) {
		Monoid L = M1;
		if (a <= 0) {
			if (check(f(L, seg[1]))) return find_subtree(1, check, L, false);
			return -1;
		}
		int b = sz;
		for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
			if (a & 1) {
				Monoid nxt = f(L, seg[a]);
				if (check(nxt)) return find_subtree(a, check, L, false);
				L = nxt;
				++a;
			}
		}
		return -1;
	}

	template< typename C >
	int find_last(int b, const C& check) {
		Monoid R = M1;
		if (b >= sz) {
			if (check(f(seg[1], R))) return find_subtree(1, check, R, true);
			return -1;
		}
		int a = sz;
		for (b += sz; a < b; a >>= 1, b >>= 1) {
			if (b & 1) {
				Monoid nxt = f(seg[--b], R);
				if (check(nxt)) return find_subtree(b, check, R, true);
				R = nxt;
			}
		}
		return -1;
	}
};

*/


vector<pair<long long, long long> > prime_factorize(long long N) {
	vector<pair<long long, long long> > res;
	for (long long a = 2; a * a <= N; ++a) {
		if (N % a != 0) continue;
		long long ex = 0;
		while (N % a == 0) {
			++ex;
			N /= a;
		}
		res.push_back({ a, ex });
	}
	if (N != 1) res.push_back({ N, 1 });
	return res;
}


Combination co;
typedef pair<int, int> pi;
priority_queue<pl, vector<pl>, greater<pl> > pqpl;


priority_queue<ll, vector<ll>, greater<ll> > pqll;


ll nck(ll n, ll k, ll m) {
	ll ans = 1;
	ll pre_ans = 1;
	if (k == 0)return 1;
	for (ll i = 1; i <= k; i++) {
		pre_ans = ans;
		ans = pre_ans * (n - i + 1);
		ans %= m;
		ans *= modinv(i, m);
		ans %= modd;
	}
	return ans;
}


ll H, W;
string S[100] = {};
void Search(bool gone[51][51], bool gone2[51][51], ll h, ll w) {

	gone[h][w] = true;
	ll offset[4][2] = { {0,-1}, {1,0},{0,1},{-1,0} };
	lp(i, 4) {
		ll next_h = h + offset[i][0];
		ll next_w = w + offset[i][1];
		if (next_h < 0 || H <= next_h)continue;
		if (next_w < 0 || W <= next_w)continue;
		if (gone[next_h][next_w])continue;
		if (S[next_h][next_w] == '#')continue;
		Search(gone, gone2, next_h, next_w);
	}

}


int main() {
	while (true) {
		cin >> H>> W;
		if (H == 0)break;

		lp(i, 100)S[i].clear();
		lp(i, H)cin >> S[i];
		string ans = "YES";
		lp(i, H) {
			lp(j, W) {
				bool gone[51][51] = {};
				bool gone2[51][51] = {};
				if (i == 0 && j == 0)continue;
				if (i == 0 && j == W-1)continue;
				if (i == H-1 && j == 0)continue;
				if (i == H-1 && j == W-1)continue;
				if (S[i][j] == '#')continue;
				S[i][j] = '#';
				Search(gone, gone2, 0, 0);
				if ((!gone[0][0]) || (!gone[H - 1][0]) || (!gone[0][W - 1]) || (!gone[H - 1][W - 1]))ans = "NO";
				S[i][j] = '.';
			}
		}
		bool gone[51][51] = {};
		bool gone2[51][51] = {};
		Search(gone, gone2, 0, 0);
		if ((!gone[0][0]) || (!gone[H - 1][0]) || (!gone[0][W - 1]) || (!gone[H - 1][W - 1]))ans = "NO";
		cout << ans << endl;
	}

	//cout << fixed << setprecision(12) << bb << endl;
	return 0;
}

/*
10
10 9 8 7 6 5 4 3 2 1

*/
accuracy: 1
time_ms: 500
memory_kb: 3684
final_rank: 13

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

using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
#define fi first
#define se second
#define N 214514
#define all(x) (x).begin(), (x).end()
// const ll mod = 1000000007;
const ll mod = 998244353;
const ll inf = 1000000000000000000;
ll n, m;
char c[55][55];
ll dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
bool func() {
    ll cnt = 0;
    vector<vector<bool>> used(n, vector<bool>(m));
    queue<P> que;
    que.push({0, 0});
    used[0][0] = 1;
    while (!que.empty()) {
        P p = que.front();
        que.pop();
        if ((p.fi == 0 || p.fi == n - 1) && (p.se == 0 || p.se == m - 1)) cnt++;
        for (int k = 0; k < 4; k++) {
            ll ny = p.fi + dy[k], nx = p.se + dx[k];
            if (!(0 <= ny && ny < n && 0 <= nx && nx < m)) continue;
            if (used[ny][nx]) continue;
            if (c[ny][nx] == '#') continue;
            used[ny][nx] = 1;
            que.push({ny, nx});
        }
    }
    return (cnt == 4);
}
void solve() {
    cin >> n >> m;
    if (!n) exit(0);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) cin >> c[i][j];
    bool ok = func();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if ((i == 0 || i == n - 1) && (j == 0 || j == m - 1)) continue;
            if (c[i][j] == '.') {
                c[i][j] = '#';
                if (!func()) ok = 0;
                c[i][j] = '.';
            }
        }
    }
    cout << (ok ? "YES\n" : "NO\n");
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    ll t = 1;
    // cin >> t;
    while (1) solve();
    return 0;
}
accuracy: 1
time_ms: 650
memory_kb: 3356
final_rank: 15

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define cinf(n,x) for(int i=0;i<(n);i++)cin>>x[i];
#define ft first
#define sc second
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define all(v) (v).begin(),(v).end()
#define LB(a,x) lb(all(a),x)-a.begin()
#define UB(a,x) ub(all(a),x)-a.begin()
#define mod 1000000007
//#define mod 998244353
#define FS fixed<<setprecision(15)
using namespace std;
typedef long long ll;
const double pi=3.141592653589793;
template<class T> using V=vector<T>;
using P=pair<ll,ll>;
typedef unsigned long long ull;
typedef long double ldouble;
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline void out(T a){ cout << a << '\n'; }
void YN(bool ok){if(ok) cout << "Yes" << endl; else cout << "No" << endl;}
//void YN(bool ok){if(ok) cout << "YES" << endl; else cout << "NO" << endl;}


const ll INF=1e18;
const int mx=200005;

int seen[55][55];

int check(int i,int j,int n,int m){
    return 0<=i&&i<n&&0<=j&&j<m;
}

int main(){
    //オーバーフローは大丈夫ですか？？
    cin.tie(0);ios::sync_with_stdio(false);
    while(true){
        int n,m;
        cin>>n>>m;
        if(n==0&&m==0) break;
        V<string> s(n);
        cinf(n,s);
        int ok=1;
        rep(I,n){
            rep(J,m){
                if(I==0&&J==0) continue;
                if(I==0&&J==m-1) continue;
                if(I==n-1&&J==0) continue;
                if(I==n-1&&J==m-1) continue;
                rep(i,n)rep(j,m)seen[i][j]=0;
                //seen[0][0]=1;
                V<int> dx={-1,1,0,0};
                V<int> dy={0,0,1,-1};
                function<void(int,int)> dfs=[&](int i,int j){
                    seen[i][j]=1;
                    rep(k,4){
                        int x=i+dx[k];
                        int y=j+dy[k];
                        if(!check(x,y,n,m)||(x==I&&y==J)) continue;
                        if(s[x][y]!='#'&&!seen[x][y])dfs(x,y);
                    }
                };
                dfs(0,0);
                int f=0;
                if(!seen[n-1][0]) f=1;
                if(!seen[n-1][m-1]) f=1;
                if(!seen[0][m-1]) f=1;
                if(f) ok=0;
            }
        }
        if(ok) out("YES");
        else out("NO");
    }
}
accuracy: 1
time_ms: 840
memory_kb: 3636
final_rank: 20

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

template <typename Cap, bool directed> struct Dinic {
    Dinic(int n) : n(n), G(n), level(n), iter(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < n);
        assert(0 <= to && to < n);
        assert(0 <= cap);
        assert(from != to);
        int m = pos.size(), from_id = G[from].size(), to_id = G[to].size();
        pos.emplace_back(from, G[from].size());
        G[from].emplace_back(to, cap, to_id);
        G[to].emplace_back(from, directed ? 0 : cap, from_id);
        return m;
    }

    int add_vertex() {
        G.emplace_back();
        level.emplace_back();
        iter.emplace_back();
        return n++;
    }

    std::tuple<int, int, Cap, Cap> get_edge(int i) {
        assert(0 <= i && i < (int)pos.size());
        auto e = G[pos[i].first][pos[i].second];
        auto re = G[e.to][e.rev];
        return {pos[i].first, e.to, e.cap + re.cap, re.cap};
    }

    std::vector<std::tuple<int, int, Cap, Cap>> edges() {
        std::vector<std::tuple<int, int, Cap, Cap>> res;
        for (size_t i = 0; i < pos.size(); i++) res.emplace_back(get_edge(i));
        return res;
    }

    void change_edge(int i, Cap new_cap, Cap new_flow) {
        assert(0 <= i && i < (int)pos.size());
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& e = G[pos[i].first][pos[i].second];
        auto& re = G[e.to][e.rev];
        e.cap = new_cap - new_flow;
        re.cap = (directed ? new_flow : new_cap + new_flow);
    }

    Cap max_flow(int s, int t) { return max_flow(s, t, std::numeric_limits<Cap>::max()); }

    Cap max_flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < n);
        assert(0 <= t && t < n);
        if (s == t) return 0;
        Cap flow = 0;
        while (flow < flow_limit) {
            bfs(s, t);
            if (level[t] < 0) break;
            std::fill(iter.begin(), iter.end(), 0);
            while (flow < flow_limit) {
                Cap f = dfs(s, t, flow_limit - flow);
                if (f == 0) break;
                flow += f;
            }
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        assert(0 <= s && s < n);
        std::vector<bool> visited(n);
        std::queue<int> que;
        visited[s] = true;
        que.emplace(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (const auto& e : G[v]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.emplace(e.to);
                }
            }
        }
        return visited;
    }

private:
    struct edge {
        int to;
        Cap cap;
        int rev;
        edge(int to, Cap cap, int rev) : to(to), cap(cap), rev(rev) {}
    };

    int n;
    std::vector<std::vector<edge>> G;
    std::vector<std::pair<int, int>> pos;
    std::vector<int> level, iter;

    void bfs(int s, int t) {
        std::fill(level.begin(), level.end(), -1);
        std::queue<int> que;
        level[s] = 0;
        que.emplace(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (const auto& e : G[v]) {
                if (e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.emplace(e.to);
                }
            }
        }
    }

    Cap dfs(int v, int t, Cap f) {
        if (v == t) return f;
        for (int& i = iter[v]; i < (int)G[v].size(); i++) {
            auto& e = G[v][i];
            if (e.cap <= 0 || level[v] >= level[e.to]) continue;
            Cap d = dfs(e.to, t, min(f, e.cap));
            if (d <= 0) continue;
            e.cap -= d;
            G[e.to][e.rev].cap += d;
            return d;
        }
        return 0;
    }
};

/**
 * @brief Dinic (Maximum flow)
 * @docs docs/flow/Dinic.md
 */

const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};

void solve(int N, int M) {
    vector<string> S(N);
    for (auto& s : S) cin >> s;

    Dinic<int, true> D(N * M * 2);
    auto IN = [&](int x, int y) { return x * M + y; };
    auto OUT = [&](int x, int y) { return IN(x, y) + N * M; };
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (S[i][j] == '#') continue;
            D.add_edge(IN(i, j), OUT(i, j), 1);
            for (int k = 0; k < 4; k++) {
                int ni = i + dx[k], nj = j + dy[k];
                if (ni < 0 or N <= ni or nj < 0 or M <= nj) continue;
                if (S[ni][nj] == '#') continue;
                D.add_edge(OUT(i, j), IN(ni, nj), 1);
            }
        }
    }

    auto D2 = D;
    int a = D.max_flow(OUT(0, 0), IN(N - 1, M - 1), 2), b = D2.max_flow(OUT(N - 1, 0), IN(0, M - 1), 2);
    cout << (a == 2 and b == 2 ? "YES" : "NO") << '\n';
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N, M;
    while (cin >> N >> M, N) solve(N, M);
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4536
final_rank: 4

code_snippet: #define LOCAL
#include <bits/stdc++.h>
using namespace std;
#pragma region Macros
typedef long long ll;
typedef __int128_t i128;
typedef unsigned int uint;
typedef unsigned long long ull;
#define ALL(x) (x).begin(), (x).end()

template <typename T> istream& operator>>(istream& is, vector<T>& v) {
    for (T& x : v) is >> x;
    return is;
}
template <typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    }
    return os;
}
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> ostream& operator<<(ostream& os, const map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T, typename U> ostream& operator<<(ostream& os, const unordered_map<T, U>& m) {
    os << '{';
    for (auto itr = m.begin(); itr != m.end();) {
        os << '(' << itr->first << ',' << itr->second << ')';
        if (++itr != m.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const unordered_set<T>& s) {
    os << '{';
    for (auto itr = s.begin(); itr != s.end();) {
        os << *itr;
        if (++itr != s.end()) os << ',';
    }
    os << '}';
    return os;
}
template <typename T> ostream& operator<<(ostream& os, const deque<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 == (int)v.size() ? "" : " ");
    }
    return os;
}

template <int i, typename T> void print_tuple(ostream&, const T&) {}
template <int i, typename T, typename H, class... Args> void print_tuple(ostream& os, const T& t) {
    if (i) os << ',';
    os << get<i>(t);
    print_tuple<i + 1, T, Args...>(os, t);
}
template <typename... Args> ostream& operator<<(ostream& os, const tuple<Args...>& t) {
    os << '{';
    print_tuple<0, tuple<Args...>, Args...>(os, t);
    return os << '}';
}

void debug_out() { cerr << '\n'; }
template <class Head, class... Tail> void debug_out(Head&& head, Tail&&... tail) {
    cerr << head;
    if (sizeof...(Tail) > 0) cerr << ", ";
    debug_out(move(tail)...);
}
#ifdef LOCAL
#define debug(...)                                                                   \
    cerr << " ";                                                                     \
    cerr << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << '\n'; \
    cerr << " ";                                                                     \
    debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

template <typename T> T gcd(T x, T y) { return y != 0 ? gcd(y, x % y) : x; }
template <typename T> T lcm(T x, T y) { return x / gcd(x, y) * y; }

int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(long long t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int botbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int botbit(long long a) { return a == 0 ? 64 : __builtin_ctzll(a); }
int popcount(signed t) { return __builtin_popcount(t); }
int popcount(long long t) { return __builtin_popcountll(t); }
bool ispow2(int i) { return i && (i & -i) == i; }

template <class T> T ceil(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <class T> T floor(T x, T y) {
    assert(y >= 1);
    return (x > 0 ? x / y : (x - y + 1) / y);
}

template <class T1, class T2> inline bool chmin(T1& a, T2 b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template <class T1, class T2> inline bool chmax(T1& a, T2 b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
#pragma endregion

#include <cassert>
#include <limits>
#include <queue>
#include <vector>

template <typename Cap, bool directed> struct Dinic {
    Dinic(int n) : n(n), G(n), level(n), iter(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < n);
        assert(0 <= to && to < n);
        assert(0 <= cap);
        assert(from != to);
        int m = pos.size(), from_id = G[from].size(), to_id = G[to].size();
        pos.emplace_back(from, G[from].size());
        G[from].emplace_back(to, cap, to_id);
        G[to].emplace_back(from, directed ? 0 : cap, from_id);
        return m;
    }

    int add_vertex() {
        G.emplace_back();
        level.emplace_back();
        iter.emplace_back();
        return n++;
    }

    std::tuple<int, int, Cap, Cap> get_edge(int i) {
        assert(0 <= i && i < (int)pos.size());
        auto e = G[pos[i].first][pos[i].second];
        auto re = G[e.to][e.rev];
        return {pos[i].first, e.to, e.cap + re.cap, re.cap};
    }

    std::vector<std::tuple<int, int, Cap, Cap>> edges() {
        std::vector<std::tuple<int, int, Cap, Cap>> res;
        for (size_t i = 0; i < pos.size(); i++) res.emplace_back(get_edge(i));
        return res;
    }

    void change_edge(int i, Cap new_cap, Cap new_flow) {
        assert(0 <= i && i < (int)pos.size());
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& e = G[pos[i].first][pos[i].second];
        auto& re = G[e.to][e.rev];
        e.cap = new_cap - new_flow;
        re.cap = (directed ? new_flow : new_cap + new_flow);
    }

    Cap max_flow(int s, int t) { return max_flow(s, t, std::numeric_limits<Cap>::max()); }

    Cap max_flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < n);
        assert(0 <= t && t < n);
        if (s == t) return 0;
        Cap flow = 0;
        while (flow < flow_limit) {
            bfs(s, t);
            if (level[t] < 0) break;
            std::fill(iter.begin(), iter.end(), 0);
            while (flow < flow_limit) {
                Cap f = dfs(s, t, flow_limit - flow);
                if (f == 0) break;
                flow += f;
            }
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        assert(0 <= s && s < n);
        std::vector<bool> visited(n);
        std::queue<int> que;
        visited[s] = true;
        que.emplace(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (const auto& e : G[v]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.emplace(e.to);
                }
            }
        }
        return visited;
    }

private:
    struct edge {
        int to;
        Cap cap;
        int rev;
        edge(int to, Cap cap, int rev) : to(to), cap(cap), rev(rev) {}
    };

    int n;
    std::vector<std::vector<edge>> G;
    std::vector<std::pair<int, int>> pos;
    std::vector<int> level, iter;

    void bfs(int s, int t) {
        std::fill(level.begin(), level.end(), -1);
        std::queue<int> que;
        level[s] = 0;
        que.emplace(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (const auto& e : G[v]) {
                if (e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.emplace(e.to);
                }
            }
        }
    }

    Cap dfs(int v, int t, Cap f) {
        if (v == t) return f;
        for (int& i = iter[v]; i < (int)G[v].size(); i++) {
            auto& e = G[v][i];
            if (e.cap <= 0 || level[v] >= level[e.to]) continue;
            Cap d = dfs(e.to, t, min(f, e.cap));
            if (d <= 0) continue;
            e.cap -= d;
            G[e.to][e.rev].cap += d;
            return d;
        }
        return 0;
    }
};

/**
 * @brief Dinic (Maximum flow)
 * @docs docs/flow/Dinic.md
 */

const int INF = 1e9;
const long long IINF = 1e18;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const char dir[4] = {'D', 'R', 'U', 'L'};
const long long MOD = 1000000007;
// const long long MOD = 998244353;

void solve(int N, int M) {
    vector<string> S(N);
    for (auto& s : S) cin >> s;

    Dinic<int, true> D(N * M * 2);
    auto IN = [&](int x, int y) { return x * M + y; };
    auto OUT = [&](int x, int y) { return IN(x, y) + N * M; };
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (S[i][j] == '#') continue;
            D.add_edge(IN(i, j), OUT(i, j), 1);
            for (int k = 0; k < 4; k++) {
                int ni = i + dx[k], nj = j + dy[k];
                if (ni < 0 or N <= ni or nj < 0 or M <= nj) continue;
                if (S[ni][nj] == '#') continue;
                D.add_edge(OUT(i, j), IN(ni, nj), 1);
            }
        }
    }

    auto D2 = D;
    int a = D.max_flow(OUT(0, 0), IN(N - 1, M - 1), 2), b = D2.max_flow(OUT(N - 1, 0), IN(0, M - 1), 2);
    cout << (a == 2 and b == 2 ? "YES" : "NO") << '\n';
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N, M;
    while (cin >> N >> M, N) solve(N, M);
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4632
final_rank: 5

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}

struct Edge{
    int to,rev; ll cap;
    Edge(int to,ll cap,int rev):to(to),cap(cap),rev(rev){}
};
// ここの値に注意！！
const int N=5200;
const ll INF=1e9;
vector<Edge> g[N];
int level[N]; 
int iter[N];
void add_edge(int s,int t,ll c){
    g[s].push_back(Edge(t,c,g[t].size()));
    g[t].push_back(Edge(s,0,g[s].size()-1));
}
void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int> q;
    level[s]=0;
    q.push(s);
    while(q.size()){
        int v=q.front(); q.pop();
        for(auto &e:g[v]){
            if(e.cap>0&&level[e.to]<0){
                level[e.to]=level[v]+1;
                q.push(e.to);
            }
        }
    }
}
ll dfs(int v,int t,ll f){
    if(v==t)return f;
    for(int &i=iter[v];i<g[v].size();i++){
        Edge &e=g[v][i];
        if(e.cap>0&&level[v]<level[e.to]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                g[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
ll max_flow(int s,int t){
    ll flow=0;
    while(1){
        bfs(s);
        if(level[t]<0)return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0){
            flow+=f;
        }
    }
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int h,w;
    while(cin >> h >> w,h){
        vector<string> s(h);
        for(int i=0;i<h;i++){
            cin >> s[i];
        }
        int S = 2*h*w;
        int t[3]={w-1,(h-1)*w,h*w-1};
        int T = 2*h*w+1;
        bool ok = true;
        for(int _=0;_<3;_++){
            for(int i=0;i<=T;i++){
                g[i].clear();
            }
            add_edge(S,0,2);
            for(int i=0;i<h;i++){
                for(int j=0;j<w;j++){
                    if(s[i][j] == '.'){
                        if(i+1<h and s[i+1][j] == '.'){
                            add_edge(i*w+j+h*w,(i+1)*w+j,1);
                            add_edge((i+1)*w+j+h*w, i*w+j, 1);
                        }
                        if(j+1<w and s[i][j+1] == '.'){
                            add_edge(i*w+j+h*w,i*w+j+1,1);
                            add_edge(i*w+j+1+h*w, i*w+j, 1);
                        }
                    }
                    if(i+j == 0 or i*w+j == t[_]){
                        add_edge(i*w+j, i*w+j+w*h, 2);
                    }
                    else{
                        add_edge(i*w+j, i*w+j+w*h, 1);
                    }
                }
            }
            add_edge(t[_]+h*w, T, 2);
            if(max_flow(S, T)<2){
                ok = false;
            }
        }
        if(ok){
            cout << "YES" << "\n";
        }
        else{
            cout << "NO" << "\n";
        }
    }
}
accuracy: 1
time_ms: 10
memory_kb: 4252
final_rank: 3