#include <bits/stdc++.h>
struct tdata {
  int position;
  int cost;
  struct tdata *next;
};
struct heapData {
  int distance;
  int position;
};
struct heapData arrHeap[2000000];
int heapCountData = 0;
struct tdata *adjListHead[200005];
int compare(struct heapData a, struct heapData b) {
  if (a.distance < b.distance) return -1;
  if (a.distance == b.distance) {
    if (a.position < b.position) return -1;
    if (a.position == b.position) return 0;
    return 1;
  }
  return 1;
}
void downHeap(struct heapData *heapArr, int idx, int ndata) {
  int toIdx = idx;
  if (2 * idx <= ndata && compare(heapArr[toIdx], heapArr[2 * idx]) > 0) {
    toIdx = 2 * idx;
  }
  if (2 * idx + 1 <= ndata &&
      compare(heapArr[toIdx], heapArr[2 * idx + 1]) > 0) {
    toIdx = 2 * idx + 1;
  }
  if (toIdx == idx) return;
  struct heapData temp = heapArr[toIdx];
  heapArr[toIdx] = heapArr[idx];
  heapArr[idx] = temp;
  downHeap(heapArr, toIdx, ndata);
}
void makeHeap(struct heapData *heapArr, int n) {
  for (int i = n / 2; i > 0; i--) {
    downHeap(heapArr, i, n);
  }
}
void popHeap(struct heapData *heapArr, int *n) {
  if (*n == 1) {
    (*n)--;
    return;
  }
  heapArr[1] = heapArr[*n];
  (*n)--;
  downHeap(heapArr, 1, *n);
}
void upHeap(struct heapData *heapArr, int idx, int ndata) {
  if (idx == 1) return;
  int ParentIdx = idx / 2;
  if (compare(heapArr[ParentIdx], heapArr[idx]) < 0) return;
  struct heapData temp = heapArr[ParentIdx];
  heapArr[ParentIdx] = heapArr[idx];
  heapArr[idx] = temp;
  upHeap(heapArr, ParentIdx, ndata);
}
void pushHeap(struct heapData *heapArr, int *n, int distance, int position) {
  (*n)++;
  heapArr[*n].distance = distance;
  heapArr[*n].position = position;
  upHeap(heapArr, *n, *n);
}
struct heapData topHeap(struct heapData *heapArr, int n) {
  if (n < 1) return {-1, -1};
  return heapArr[1];
}
void pushList(struct tdata **localHead, int position, int cost) {
  struct tdata *newnode = (struct tdata *)malloc(sizeof(struct tdata));
  newnode->position = position;
  newnode->cost = cost;
  newnode->next = NULL;
  if (*localHead == NULL) {
    *localHead = newnode;
  } else {
    newnode->next = *localHead;
    *localHead = newnode;
  }
}
void popAll(struct tdata **localHead) {
  while (*localHead != NULL) {
    struct tdata *del = *localHead;
    *localHead = (*localHead)->next;
    free(del);
  }
}
struct print {
  int prevLevel;
  int nextLevel;
};
struct print track[100005];
int distance[200005];
int visited[200005];
int par[200005];
int idx = 1;
int prim(struct tdata **localAdjList, int V, int a, int r, int c) {
  heapCountData = 0;
  for (int i = 0; i <= V; i++) {
    distance[i] = r * c;
    visited[i] = 0;
    par[i] = 0;
  }
  pushHeap(arrHeap, &heapCountData, r * c, a);
  int mstCost = 0;
  while (heapCountData > 0) {
    struct heapData topData = topHeap(arrHeap, heapCountData);
    popHeap(arrHeap, &heapCountData);
    int curPosition = topData.position;
    int curDist = topData.distance;
    if (visited[curPosition]) continue;
    visited[curPosition] = 1;
    mstCost += curDist;
    track[idx].nextLevel = curPosition;
    track[idx++].prevLevel = par[curPosition];
    struct tdata *current = localAdjList[curPosition];
    while (current != NULL) {
      if (visited[current->position] == 0) {
        if (current->cost >= distance[current->position]) {
          pushHeap(arrHeap, &heapCountData, distance[current->position],
                   current->position);
        } else {
          pushHeap(arrHeap, &heapCountData, current->cost, current->position);
          par[current->position] = curPosition;
          distance[current->position] = current->cost;
        }
      }
      current = current->next;
    }
  }
  return mstCost;
}
char map[1005][15][15];
int main() {
  int r, c, l, w;
  scanf("%d %d %d %d", &r, &c, &l, &w);
  getchar();
  for (int i = 1; i <= l; i++) {
    for (int j = 0; j < r; j++) {
      for (int k = 0; k < c; k++) {
        scanf("%c", &map[i][j][k]);
      }
      getchar();
    }
  }
  for (int i = 0; i <= l; i++) {
    adjListHead[i] = NULL;
  }
  int diff = 0;
  for (int i = 1; i <= l - 1; i++) {
    for (int ii = i + 1; ii <= l; ii++) {
      diff = 0;
      for (int j = 0; j < r; j++) {
        for (int k = 0; k < c; k++) {
          if (map[i][j][k] != map[ii][j][k]) {
            diff++;
          }
        }
      }
      pushList(&adjListHead[i], ii, diff * w);
      pushList(&adjListHead[ii], i, diff * w);
    }
  }
  int mstCost = prim(adjListHead, l, 1, r, c);
  printf("%d\n", mstCost);
  for (int i = 1; i < idx; i++) {
    printf("%d %d\n", track[i].nextLevel, track[i].prevLevel);
  }
  for (int i = 0; i <= l; i++) {
    popAll(&adjListHead[i]);
  }
  return 0;
}
