// includes {{{
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<tuple>
#include<cmath>
#include<random>
#include<cassert>
#include<bitset>
#include<cstdlib>
// #include<deque>
// #include<multiset>
#include<cstring>
// #include<bits/stdc++.h>
// }}}
using namespace std;
using ll = long long;

string s[185];
const int C = 16;

int dp[2][185 + 1][185 + 1][185 + 1];
int h, w;

// accum2D range2D range2Dloop {{{
#include <type_traits>
using loop2d_int = long long;
template < class T >
void accum2D(T &val, int h, int w) {
  for(int i = 1; i < h; i++)
    for(int j = 0; j < w; j++) val[i][j] += val[i - 1][j];
  for(int i = 0; i < h; i++)
    for(int j = 1; j < w; j++) val[i][j] += val[i][j - 1];
}

template < class T,
         class V = typename std::remove_reference< decltype(T()[0][0]) >::type >
         V range2D(T &val, int y1, int x1, int y2, int x2, int h, int w) {
           if(y2 >= h) y2 = h - 1;
           if(x2 >= w) x2 = w - 1;
           if(y1 > y2 || x1 > x2) return static_cast< V >(0);
           V res(val[y2][x2]);
           if(y1 - 1 >= 0) res -= val[y1 - 1][x2];
           if(x1 - 1 >= 0) res -= val[y2][x1 - 1];
           if(y1 - 1 >= 0 && x1 - 1 >= 0) res += val[y1 - 1][x1 - 1];
           return res;
         }

template < class T,
         class V = typename std::remove_reference< decltype(T()[0][0]) >::type >
         auto range2Dloop(T &val, loop2d_int ty1, loop2d_int tx1, loop2d_int y2, loop2d_int x2,
             int h, int w) {
           if(ty1 > y2 || tx1 > x2) return static_cast< V >(0);

           loop2d_int y1 = ty1 % h;
           if(y1 < 0) y1 += h;
           loop2d_int x1 = tx1 % w;
           if(x1 < 0) x1 += w;

           y2 += y1 - ty1;
           x2 += x1 - tx1;

           loop2d_int gy = y2 / h;
           loop2d_int gx = x2 / w;
           y2 %= h;
           x2 %= w;

           V res(0);
           if(gy == 0 && gx == 0) {
             res += range2D< T >(val, y1, x1, y2, x2, h, w);
           } else if(gy == 0) {
             res += range2D< T >(val, y1, x1, y2, w - 1, h, w);
             res += range2D< T >(val, y1, 0, y2, x2, h, w);
             res += range2D< T >(val, y1, 0, y2, w - 1, h, w) * (gx - 1);
           } else if(gx == 0) {
             res += range2D< T >(val, y1, x1, h - 1, x2, h, w);
             res += range2D< T >(val, 0, x1, y2, x2, h, w);
             res += range2D< T >(val, 0, x1, h - 1, x2, h, w) * (gy - 1);
           } else {
             res += range2D< T >(val, y1, x1, h - 1, w - 1, h, w);                     // UL
             res += range2D< T >(val, 0, x1, y2, w - 1, h, w);                         // DL
             res += range2D< T >(val, y1, 0, h - 1, x2, h, w);                         // UR
             res += range2D< T >(val, 0, 0, y2, x2, h, w);                             // DR
             res += range2D< T >(val, y1, 0, h - 1, w - 1, h, w) * (gx - 1);           // U
             res += range2D< T >(val, 0, 0, y2, w - 1, h, w) * (gx - 1);               // D
             res += range2D< T >(val, 0, x1, h - 1, w - 1, h, w) * (gy - 1);           // L
             res += range2D< T >(val, 0, x1, h - 1, x2, h, w) * (gy - 1);              // R
             res += range2D< T >(val, 0, 0, h - 1, w - 1, h, w) * (gy - 1) * (gx - 1); // C
           }
           return res;
         }
// }}}

template <class T, class U> inline void smax(T &a, U b) { a = a > b ? a : b; }
template <class T, class U> inline void smin(T &a, U b) { a = a < b ? a : b; }

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> h >> w;
  vector<vector<int>> f(h, vector<int>(w, 0));
  for(int i = 0; i < h; i++) {
    cin >> s[i];
    for(int j = 0; j < w; j++) if(s[i][j] == '.') f[i][j] = 1;
  }
  accum2D(f, h, w);

  auto isMonotone = [&] (int r1, int c1, int r2, int c2) {
    int x = range2D(f, r1, c1, r2, c2, h, w);
    return x == (r2 - r1 + 1) * (c2 - c1 + 1) || x == 0;
  };

  // i = 0 : 累積和を使っていい感じに求める
  for(int rr = 0; rr < h; rr++) for(int r1 = 0; r1 + rr < h; r1++) {
    int r2 = r1 + rr;
    int c1 = 0, c2 = 0;
    for(;c2 < w; ) {
      while(c2 < w && isMonotone(r1, c1, r2, c2)) c2++;
      if(c1 == c2) {
        dp[0][r1][c1][r2] = c2-1;
        c1++, c2++;
      } else {
        for(;c1 < c2; c1++) {
          dp[0][r1][c1][r2] = c2-1;
        }
      }
    }
  }
  for(int cc = 0; cc < w; cc++) for(int c1 = 0; c1 + cc < w; c1++) {
    int c2 = c1 + cc;
    int r1 = 0, r2 = 0;
    for(;r2 < h; ) {
      while(r2 < h && isMonotone(r1, c1, r2, c2)) r2++;
      if(r1 == r2) {
        dp[1][r1][c1][c2] = r2-1;
        r1++, r2++;
      } else {
        for(;r1 < r2; r1++) {
          dp[1][r1][c1][c2] = r2-1;
        }
      }
    }
  }


  int i = 0;
  while(dp[0][0][0][h-1] < w - 1) {
    assert(i < C);
    i++;
    // for(int r1 = 0; r1 < h; r1++) for(int c1 = 0; c1 < w; c1++) {
    //   for(int r2 = r1; r2 < h; r2++) dp[0][r1][c1][r2][i] = dp[0][r1][c1][r2][i-1], dump(i, r1, c1, r2, dp[0][r1][c1][r2][i-1]);
    //   for(int c2 = c1; c2 < w; c2++) dp[1][r1][c1][c2][i] = dp[1][r1][c1][c2][i-1], dump(i, r1, c1, c2, dp[1][r1][c1][c2][i-1]);
    // }
    for(int r1 = 0; r1 < h; r1++) for(int c1 = 0; c1 < w; c1++) {
      // 伸ばしたい方向と垂直に切る場合
      for(int r2 = r1; r2 < h; r2++) {
        // int &d = dp[0][r1][c1][r2][i];
        // int c2 = dp[0][r1][c1][r2][i-1] + 1;
        // if(c2 == w) d = w - 1;
        // else smax(d, dp[0][r1][c2][r2][i-1]);
        // 次元を一個減らしても矛盾は生じない
        int &d = dp[0][r1][c1][r2];
        int c2 = d + 1;
        if(c2 == w) d = w - 1;
        else smax(d, dp[0][r1][c2][r2]);
      }
      for(int c2 = c1; c2 < w; c2++) {
        int &d = dp[1][r1][c1][c2];
        int r2 = d + 1;
        if(r2 == h) d = h - 1;
        else smax(d, dp[1][r2][c1][c2]);
      }
      // 伸ばしたい方向と水平に切る場合
      {
        int c2 = w - 1, r2 = r1;
        for(;c2 >= c1; c2--) {
          for(;r2 < h && r2 <= dp[1][r1][c1][c2]; r2++) {
            smax(dp[0][r1][c1][r2], c2);
          }
        }
      }
      {
        int c2 = c1, r2 = h - 1;
        for(;r2 >= r1; r2--) {
          for(;c2 < w && c2 <= dp[0][r1][c1][r2]; c2++) {
            smax(dp[1][r1][c1][c2], r2);
          }
        }
      }
    }
  }

  cout << i << endl;

  return 0;
}


Measured memory_bytes: 50560