#include <iostream>
#include <string>
#include <vector>
#include <climits>
#include <set>
#include <algorithm>
#include <unordered_map>
#include <queue>
#include <iomanip>
#include <map>
#include <utility>
#include <numeric>
#include <chrono>
#include <ctime>
#include <cassert>
#include <bitset>
#include <iterator>
#include <cmath>
#include <stack>
#include <random>

#define rep(i,n) for(int i=0; i<(int)(n); i++)
#define debug(x) cerr << #x << ": " << x << ", "
#define debugln(x) cerr << #x << ": " << x << '\n'

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

using namespace std;
using ll = long long;
using P = pair<ll, ll>;

//constexpr ll mod = 998244353;
constexpr ll mod = 1e9+7;
const double PI = acos(-1.0);
mt19937_64 engine(chrono::steady_clock::now().time_since_epoch().count());

short dp1[186][186][186][17];
short dp2[186][186][186][17];

bool check(int x1, int x2, int y1, int y2, int cnt) {
  auto xm = dp2[y1][y2][x1][cnt-1];
  if (xm > x2 || dp2[y1][y2][xm][cnt-1] > x2) {
    return true;
  }
  auto ym = dp1[x1][x2][y1][cnt-1];
  if (ym > y2 || dp1[x1][x2][ym][cnt-1] > y2) {
    return true;
  }
  return false;
}

signed main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  int h, w; cin >> h >> w;
  bool mat[h][w];
  rep(i, h) {
    rep(j, w) {
      char c; cin >> c;
      mat[i][j] = (c == '.');
    }
  }

  rep(i, h) {
    int k = 0;
    rep(j, w-1) {
      if (mat[i][j] != mat[i][j+1]) {
        while(k <= j) {
          dp1[i][i][k][0] = j+1;
          k++;
        }
      }
    }
    while(k < w) {
      dp1[i][i][k][0] = w;
      k++;
    }
  }

  rep(j, w) {
    int k = 0;
    rep(i, h-1) {
      if (mat[i][j] != mat[i+1][j]) {
        while(k <= i) {
          dp2[j][j][k][0] = i+1;
          k++;
        }
      }
    }
    while(k < h) {
      dp2[j][j][k][0] = h;
      k++;
    }
  }

  rep(i, h) {
    rep(j, w) {
      for(int k=j+1; k<w; k++) {
        if (mat[i][j] == mat[i][k]) {
          dp2[j][k][i][0] = min(dp2[j][k-1][i][0], dp2[k][k][i][0]);
        } else {
          dp2[j][k][i][0] = i;
        }
      }
    }
  }

  rep(i, w) {
    rep(j, h) {
      for(int k=j+1; k<h; k++) {
        if (mat[j][i] == mat[k][i]) {
          dp1[j][k][i][0] = min(dp1[j][k-1][i][0], dp1[k][k][i][0]);
        } else {
          dp1[j][k][i][0] = i;
        }
      }
    }
  }

  for(int cnt=1; cnt<17; cnt++) {
    rep(x1, h) {
      for(int x2=x1; x2<h; x2++) {
        int y2 = w-1;
        int y1 = w-1;
        while(y1>=0) {
          if (check(x1, x2, y1, y2, cnt)) {
            dp1[x1][x2][y1][cnt] = y2+1;
            y1--;
          } else {
            y2--;
            if (y1>y2) {
              dp1[x1][x2][y1][cnt] = y1;
              y1--;
            }
          }
        }
      }
    }

    rep(y1, w) {
      for(int y2=y1; y2<w; y2++) {
        int x1 = h-1;
        int x2 = h-1;
        while(x1>=0) {
          if (check(x1, x2, y1, y2, cnt)) {
            dp2[y1][y2][x1][cnt] = x2+1;
            x1--;
          } else {
            x2--;
            if (x1>x2) {
              dp2[y1][y2][x1][cnt] = x1;
              x1--;
            }
          }
        }
      }
    }
  }

  rep(i, 17) {
    if (dp1[0][h-1][0][i] == w) {
      cout << i << endl;
      return 0;
    }
  }
}


Measured memory_bytes: 426240