/*
 * D.cpp
 *
 *  Created on: Oct 11, 2013
 *      Author: Hesham
 */
#include<iostream>
#include<string>
#include<map>
#include<ctime>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<cstring>
#include<bitset>
#include<fstream>
#include<cmath>
#include<cassert>
#include <stdio.h>
#include<ctype.h>
using namespace std;
int dx[] = { 0, 0, 1, -1, 0 };
int dy[] = { 0, 1, 0, 0, -1 };
int w, h, n;
string house[16];
struct State {
	vector<int> y, x;
	State() {
		x.resize(3, 0);
		y.resize(3, 0);
	}
	State(vector<int>& yy, vector<int>& xx) :
			x(xx), y(yy) {
	}
	bool operator ==(const State& other) const {
		return x == other.x && y == other.y;
	}
};
bool vis1[16][16][16][16][16][16];
bool vis2[16][16][16][16][16][16];
//short dist[16][16][16][16][16][16];

bool isVis(State& s, bool vis[16][16][16][16][16][16]) {
	return vis[s.x[0]][s.x[1]][s.x[2]][s.y[0]][s.y[1]][s.y[2]];
}
void setVis(State& s, bool vis[16][16][16][16][16][16]) {
	vis[s.x[0]][s.x[1]][s.x[2]][s.y[0]][s.y[1]][s.y[2]] = true;
}
/*int getDist(State& s) {
	return dist[s.x[0]][s.x[1]][s.x[2]][s.y[0]][s.y[1]][s.y[2]];
}*/
/*void setDist(State& s, int v) {
	dist[s.x[0]][s.x[1]][s.x[2]][s.y[0]][s.y[1]][s.y[2]] = v;
}*/

bool ok(int y, int x) {
	if (y < 0 || y == h || x < 0 || x == w)
		return false;
	if (house[y][x] == '#')
		return false;
	return true;
}
int d1, d2;
int c11, c12, c21, c22;
int pushAdjs(int i, State& adj, State& curr, queue<State>& q,
		bool visA[16][16][16][16][16][16], bool visB[16][16][16][16][16][16], int da, int db, int& c) {
	if (i == n) {
		if (isVis(adj, visA))
			return -1;
		if (isVis(adj, visB))
			return da + 1 + db;
		setVis(adj, visA);
		q.push(adj);
		++c;
		return -1;
	}
	for (int d = 0; d < 5; ++d) {
		adj.y[i] = dy[d] + curr.y[i];
		adj.x[i] = dx[d] + curr.x[i];
		if (!ok(adj.y[i], adj.x[i]))
			continue;
		bool okk = true;
		for (int j = 0; j < i; ++j) {
			if (adj.y[i] == curr.y[j] && adj.x[i] == curr.x[j]&&
			    adj.y[j] == curr.y[i] && adj.x[j] == curr.x[i]) {
				okk = false;
				break;
			}
			if (adj.y[i] == adj.y[j] && adj.x[i] == adj.x[j]) {
				okk = false;
				break;
			}
		}
		if (!okk)
			continue;
		int cost = pushAdjs(i + 1, adj, curr, q, visA, visB, da, db, c);
		if (cost != -1)
			return cost;
	}
	return -1;
}
int meetMiddle(vector<int>& sy, vector<int>& sx, vector<int>& ty,
		vector<int>& tx) {
	memset(vis1, false, sizeof vis1);
	memset(vis2, false, sizeof vis2);
	State s(sy, sx);
	State t(ty, tx);
	//setDist(s, 0);
	//setDist(t, 0);
	d1 = 0;
	d2 = 0;
	c11 = 1, c12 = 0, c21 = 1, c22 = 0;
	setVis(s, vis1);
	setVis(t, vis2);
	queue<State> q1;
	queue<State> q2;
	q1.push(s);
	q2.push(t);
	while (true) {
		if(d1 <= d2)
		{
			State curr1 = q1.front();
			q1.pop();
			--c11;
			State adj;
			int cost = pushAdjs(0, adj, curr1, q1, vis1, vis2, d1, d2, c12);
			if (cost != -1)
				return cost;
			if(!c11){
				swap(c11, c12);
				d1++;
			}
		}
		if(d2 < d1)
		{
			State curr2 = q2.front();
			q2.pop();
			--c21;
			State adj;
			int cost = pushAdjs(0, adj, curr2, q2, vis2, vis1, d2, d1, c22);
			if (cost != -1)
				return cost;
			if(!c21){
				swap(c21, c22);
				d2++;
			}
		}
	}
	return -1;
}

int main() {

	//freopen("in.txt", "r", stdin);
	//clock_t begin = clock();
	string line;
	while (cin >> w >> h >> n) {
		if (!w && !h && !n)
			break;
		cin.ignore();
		//cin.ignore();
		for (int i = 0; i < h; ++i)
			getline(cin, house[i]);

		vector<int> sx(3, 0);
		vector<int> sy(3, 0);

		vector<int> tx(3, 0);
		vector<int> ty(3, 0);
		for (int i = 0; i < h; ++i) {
			for (int j = 0; j < w; ++j) {
				if (house[i][j] >= 'A' && house[i][j] <= 'C') {
					tx[(house[i][j] - 'A')] = j;
					ty[(house[i][j] - 'A')] = i;
				}
				if (house[i][j] >= 'a' && house[i][j] <= 'c') {
					sx[(house[i][j] - 'a')] = j;
					sy[(house[i][j] - 'a')] = i;
				}
			}
		}

		cout << meetMiddle(sy, sx, ty, tx) << endl;
	}
}

Measured memory_bytes: 41520