#include <bits/stdc++.h>
using namespace std;
vector<int> parents;
vector<int> ranks;
int find_parent(int a) {
  int pa = parents[a];
  if (pa != a) {
    parents[a] = find_parent(pa);
  }
  return parents[a];
}
bool make_union(int a, int b) {
  int pa = find_parent(a);
  int pb = find_parent(b);
  if (pa == pb) {
    return false;
  }
  int ra = ranks[a];
  int rb = ranks[b];
  if (ra <= rb) {
    parents[pa] = pb;
    if (ra == rb) {
      ++ranks[pb];
    }
  } else {
    parents[pb] = pa;
  }
  return true;
}
class Edge {
 public:
  int x, y;
  long long cost;
  Edge(int x, int y, long long cost) : x(x), y(y), cost(cost) {}
};
int main() {
  cin.sync_with_stdio(false);
  cin.tie(nullptr);
  int N, M, K, W;
  cin >> N >> M >> K >> W;
  parents.reserve(K + 1);
  ranks.resize(K + 1, 1);
  vector<vector<string>> levels;
  levels.reserve(K);
  string s;
  getline(cin, s);
  for (int j = 0; j < K; ++j) {
    parents.push_back(j);
    vector<string> level;
    level.reserve(N);
    for (int i = 0; i < N; ++i) {
      string s;
      s.reserve(M + 2);
      getline(cin, s);
      level.push_back(s);
    }
    levels.push_back(level);
  }
  parents.push_back(K);
  vector<Edge> edges;
  edges.reserve((K + 1) * (K + 1));
  for (int j = 1; j <= K; ++j) {
    edges.push_back(Edge(j, 0, N * M));
  }
  for (int j = 0; j < K; ++j) {
    for (int i = j + 1; i < K; ++i) {
      int cost = 0;
      for (int ii = 0; ii < N; ++ii) {
        for (int jj = 0; jj < M; ++jj) {
          if (levels[j][ii][jj] != levels[i][ii][jj]) {
            ++cost;
          }
        }
      }
      cost = cost * W;
      edges.push_back(Edge(i + 1, j + 1, cost));
      edges.push_back(Edge(j + 1, i + 1, cost));
    }
  }
  sort(edges.begin(), edges.end(),
       [](Edge e1, Edge e2) { return e1.cost < e2.cost; });
  long long ww = 0;
  vector<pair<int, int>> res;
  res.reserve(K + 1);
  vector<vector<int>> fr;
  fr.reserve(K + 1);
  for (int j = 0; j < K + 2; ++j) {
    vector<int> tmp;
    tmp.reserve(K + 1);
    fr.push_back(tmp);
  }
  for (auto edge : edges) {
    find_parent(edge.x);
    find_parent(edge.y);
    if (make_union(edge.x, edge.y)) {
      ww += edge.cost;
      res.push_back(make_pair(edge.x, edge.y));
      fr[edge.x].push_back(edge.y);
      fr[edge.y].push_back(edge.x);
    }
  }
  cout << ww << "\n";
  vector<int> top;
  top.reserve(K + 1);
  top.push_back(0);
  vector<bool> visited;
  visited.resize(K + 1, false);
  visited[0] = true;
  while (!top.empty()) {
    int tt = top[top.size() - 1];
    top.pop_back();
    for (int j : fr[tt]) {
      if (visited[j]) {
        continue;
      }
      cout << j << " " << tt << "\n";
      visited[j] = 1;
      top.push_back(j);
    }
  }
  return 0;
}
