#include <iostream> // using g++ -Wall -std=c++14
#include <vector>
#include <set>
#include <bitset>
#include <numeric>
using namespace std;

int m, n, ans; // room of m x n dimensions
vector<string> floorPlan; // each string is 4 char long composed of '0' and '1'
vector<int> parent, ranks; // each room is a seperate component in worst case

int findSet(int x) {
  if(parent[x] != x)
    parent[x] = findSet(parent[x]);
  return parent[x];
}

void unionSet(int x, int y) {
  int px = findSet(x);
  int py = findSet(y);

  if(ranks[px] > ranks[py])
    parent[py] = px;
  else
    parent[px] = py;

  if(ranks[px] == ranks[py])
    ranks[py]++;
}

void inp() {
  string temp;

  cin >> m >> n;

  for(int i=0; i<m; i++)
    for(int j=0; j<n; j++) {
      cin >> temp;
      floorPlan.push_back(temp);
    }
}

void solve() {
  // set up Disjoint Sets
  parent.resize(m*n);
  ranks.resize(m*n, 0);
  iota(parent.begin(), parent.end(), 0);

  for(int i=0; i<m; i++)
    for(int j=0; j<n; j++) {
      bitset<4> tile(floorPlan[i*n+j]);

      // process West wall
      if(j > 0 && (tile[3] == 0))
        unionSet(i*n+j, i*n+j-1);

      // process North wall
      if(i > 0 && (tile[2] == 0))
        unionSet(i*n+j, (i-1)*n+j);
    }

  set<int> temp;
  for(int i=0; i<m*n; i++) {
    // normalise each tile
    parent[i] = findSet(parent[i]);
    temp.insert(parent[i]);
  }

  ans = temp.size();
}

void outp() {
  for(int i=0; i<m; i++) {
    for(int j=0; j<n; j++)
      cout << parent[i*n+j] << "  ";
    cout << endl;
  }

  cout << "\n" << ans << endl;
}

int main() {
  inp();
  solve();
  outp();
  return 0;
}
