#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

int width, height, n;
int encode(const int x[3], const int y[3]) {
  int ret = 0;
  int base = 1;
  REP(i, n) {
    assert(x[i] > 0 && x[i] < width - 1 && y[i] > 0 && y[i] < height - 1);
    ret += x[i] * base;
    base *= 16;
    ret += y[i] * base;
    base *= 16;
  }
  assert(ret > 0 && ret < 16 * 16 * 16 * 16 * 16 * 16);
  return ret;
}

void decode(int code, int x[3], int y[3]) {
  REP(i, n) {
    x[i] = code % 16;
    code /= 16;
    y[i] = code % 16;
    code /= 16;
  }
}

char field[20][20];
int sx[3];
int sy[3];
int gx[3];
int gy[3];
int x[3];
int y[3];
int nx[3];
int ny[3];
bool visit[16*16*16*16*16*16];
const int dx[5] = { 1, 0, -1, 0, 0 };
const int dy[5] = { 0, 1, 0, -1, 0 };

int main() {
  while (scanf("%d %d %d", &width, &height, &n), width|height|n) {
    fgets(field[0], 19, stdin);
    MEMSET(visit, false);
    MEMSET(field, '#');
    {
      REP(y, height) {
        fgets(field[y], 19, stdin);
        REP(x, width) {
          if (field[y][x] == 'A') { gx[0] = x; gy[0] = y; }
          if (field[y][x] == 'B') { gx[1] = x; gy[1] = y; }
          if (field[y][x] == 'C') { gx[2] = x; gy[2] = y; }
          if (field[y][x] == 'a') { sx[0] = x; sy[0] = y; }
          if (field[y][x] == 'b') { sx[1] = x; sy[1] = y; }
          if (field[y][x] == 'c') { sx[2] = x; sy[2] = y; }
        }
        //cout << field[y];
      }
    }
    queue<pair<int, int> > que;
    que.push(make_pair(encode(sx, sy), 0));
    visit[encode(sx, sy)] = true;
    while (!que.empty()) {
      decode(que.front().first, x, y);
      int cost = que.front().second;
      que.pop();
      //cout << x[0] << " " << y[0] << " " << x[1] << " " << y[1] << " " << cost << endl;
      REP(i, n) {
        if (x[i] != gx[i] || y[i] != gy[i]) { break; }
        if (i == n - 1) {
          printf("%d\n", cost);
          goto next;
        }
      }
      REP(dir1, 5) {
        nx[0] = x[0] + dx[dir1];
        ny[0] = y[0] + dy[dir1];
        if (n >= 1 && field[ny[0]][nx[0]] == '#') { continue; }
        REP(dir2, 5) {
          if (n < 2 && dir2 != 4) { continue; }
          nx[1] = x[1] + dx[dir2];
          ny[1] = y[1] + dy[dir2];
          if (n >= 2) {
            if (nx[0] == nx[1] && ny[0] == ny[1]) { continue; }
            if (x[0] == nx[1] && x[1] == nx[0] && y[0] == ny[1] && y[1] == ny[0]) { continue; }
          }
          if (n >= 2 && field[ny[1]][nx[1]] == '#') { continue; }
          REP(dir3, 5) {
            if (n < 3 && dir3 != 4) { continue; }
            nx[2] = x[2] + dx[dir3];
            ny[2] = y[2] + dy[dir3];
            if (n >= 3 && field[ny[2]][nx[2]] == '#') { continue; }
            if (n >= 3) {
              if (nx[0] == nx[2] && ny[0] == ny[2]) { continue; }
              if (nx[1] == nx[2] && ny[1] == ny[2]) { continue; }
              if (x[0] == nx[2] && x[2] == nx[0] && y[0] == ny[2] && y[2] == ny[0]) { continue; }
              if (x[1] == nx[2] && x[2] == nx[1] && y[1] == ny[2] && y[2] == ny[1]) { continue; }
            }
            int code = encode(nx, ny);
            if (visit[code]) { continue; }
            visit[code] = true;
            que.push(make_pair(code, cost + 1));
          }
        }
      }
    }
next:;
  }
}

Measured memory_bytes: 18000