#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
//#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define BIG_NUM 32767


struct Info{
	void set(int arg_row,int arg_col){
		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

struct Data{
	bool operator<(const struct Data &arg)const{
		return total_cost > arg.total_cost;
	}
	void set(short arg_total_cost,bool arg_cleard_1,bool arg_cleard_2,bool arg_cleard_3){
		total_cost = arg_total_cost;
		cleard_1 = arg_cleard_1;
		cleard_2 = arg_cleard_2;
		cleard_3 = arg_cleard_3;
	}
	short total_cost;
	Info loc_1,loc_2,loc_3;
	bool cleard_1,cleard_2,cleard_3;
};

Info start_info[3],goal_info[3];

string line;
int W,H,N;
short min_cost1[16][16];
short min_cost2[16][16][16][16];
short min_cost3[16][16][16][16][16][16];
int diff_row[5] = {-1,0,0,0,1},diff_col[5] = {0,-1,0,1,0};
char table[16][17];


bool is_Same(Info a,Info b){

	if(a.row == b.row && a.col == b.col){
		return true;
	}else{
		return false;
	}
}


void calc3(){

	for(int a = 0; a < H; a++){
		for(int b = 0; b < W; b++){
			for(int c = 0; c < H; c++){
				for(int d = 0; d < W; d++){
					for(int e = 0; e < H; e++){
						for(int f = 0; f < W; f++)min_cost3[a][b][c][d][e][f] = BIG_NUM;
					}
				}
			}
		}
	}

	priority_queue<Data> Q;
	min_cost3[start_info[0].row][start_info[0].col][start_info[1].row][start_info[1].col][start_info[2].row][start_info[2].col] = 0;
	Data first;
	first.total_cost = 0;
	first.loc_1 = start_info[0];
	first.loc_2 = start_info[1];
	first.loc_3 = start_info[2];
	first.cleard_1 = is_Same(start_info[0],goal_info[0]);
	first.cleard_2 = is_Same(start_info[1],goal_info[1]);
	first.cleard_3 = is_Same(start_info[2],goal_info[2]);
	Q.push(first);

	Info next_loc1,next_loc2,next_loc3;

	while(!Q.empty()){

		if(Q.top().cleard_1 == true && Q.top().cleard_2 == true && Q.top().cleard_3 == true){
			Q.pop();
		}else if(Q.top().total_cost > min_cost3[Q.top().loc_1.row][Q.top().loc_1.col][Q.top().loc_2.row][Q.top().loc_2.col][Q.top().loc_3.row][Q.top().loc_3.col]){
			Q.pop();
		}else{

			for(int i = 0; i < 5; i++){
				next_loc1.set(Q.top().loc_1.row+diff_row[i],Q.top().loc_1.col+diff_col[i]);
				if(table[next_loc1.row][next_loc1.col] == '#')continue;

				for(int k = 0; k < 5; k++){
					next_loc2.set(Q.top().loc_2.row+diff_row[k],Q.top().loc_2.col+diff_col[k]);
					if((table[next_loc2.row][next_loc2.col] == '#') || (is_Same(next_loc1,next_loc2) == true) ||
								(is_Same(next_loc1,Q.top().loc_2) == true && is_Same(next_loc2,Q.top().loc_1)))continue;
					for(int p = 0; p < 5; p++){

						next_loc3.set(Q.top().loc_3.row+diff_row[p],Q.top().loc_3.col+diff_col[p]);
						if((table[next_loc3.row][next_loc3.col] == '#') || (is_Same(next_loc1,next_loc3) == true) ||
								(is_Same(next_loc2,next_loc3) == true) || (is_Same(next_loc1,Q.top().loc_3) == true && is_Same(next_loc3,Q.top().loc_1)) ||
								(is_Same(next_loc2,Q.top().loc_3) == true && is_Same(next_loc3,Q.top().loc_2)))continue;

						if(min_cost3[next_loc1.row][next_loc1.col][next_loc2.row][next_loc2.col][next_loc3.row][next_loc3.col] > Q.top().total_cost+1){
							min_cost3[next_loc1.row][next_loc1.col][next_loc2.row][next_loc2.col][next_loc3.row][next_loc3.col] = Q.top().total_cost+1;
							Data new_data;
							new_data.loc_1 = next_loc1;
							new_data.loc_2 = next_loc2;
							new_data.loc_3 = next_loc3;
							new_data.total_cost = Q.top().total_cost+1;
							new_data.cleard_1 = is_Same(next_loc1,goal_info[0]);
							new_data.cleard_2 = is_Same(next_loc2,goal_info[1]);
							new_data.cleard_3 = is_Same(next_loc3,goal_info[2]);
							Q.push(new_data);
						}
					}
				}
			}
			Q.pop();
		}
	}

	printf("%d\n",min_cost3[goal_info[0].row][goal_info[0].col][goal_info[1].row][goal_info[1].col][goal_info[2].row][goal_info[2].col]);
}

void calc2(){

	for(int a = 0; a < H; a++){
		for(int b = 0; b < W; b++){
			for(int c = 0; c < H; c++){
				for(int d = 0; d < W; d++)min_cost2[a][b][c][d] = BIG_NUM;
			}
		}
	}

	priority_queue<Data> Q;
	min_cost2[start_info[0].row][start_info[0].col][start_info[1].row][start_info[1].col] = 0;
	Data first;
	first.total_cost = 0;
	first.loc_1 = start_info[0];
	first.loc_2 = start_info[1];
	first.cleard_1 = is_Same(start_info[0],goal_info[0]);
	first.cleard_2 = is_Same(start_info[1],goal_info[1]);
	Q.push(first);

	Info next_loc1,next_loc2;

	while(!Q.empty()){

		if(Q.top().cleard_1 == true && Q.top().cleard_2 == true){
			Q.pop();
		}else if(Q.top().total_cost > min_cost2[Q.top().loc_1.row][Q.top().loc_1.col][Q.top().loc_2.row][Q.top().loc_2.col]){
			Q.pop();
		}else{

			for(int i = 0; i < 5; i++){
				next_loc1.set(Q.top().loc_1.row+diff_row[i],Q.top().loc_1.col+diff_col[i]);
				if(table[next_loc1.row][next_loc1.col] == '#')continue;
				for(int k = 0; k < 5; k++){

					next_loc2.set(Q.top().loc_2.row+diff_row[k],Q.top().loc_2.col+diff_col[k]);
					if((table[next_loc2.row][next_loc2.col] == '#') || (is_Same(next_loc1,next_loc2) == true) ||
							(is_Same(next_loc1,Q.top().loc_2) == true && is_Same(next_loc2,Q.top().loc_1)))continue;

					if(min_cost2[next_loc1.row][next_loc1.col][next_loc2.row][next_loc2.col] > Q.top().total_cost+1){
						min_cost2[next_loc1.row][next_loc1.col][next_loc2.row][next_loc2.col] = Q.top().total_cost+1;
						Data new_data;
						new_data.loc_1 = next_loc1;
						new_data.loc_2 = next_loc2;
						new_data.total_cost = Q.top().total_cost+1;
						new_data.cleard_1 = is_Same(next_loc1,goal_info[0]);
						new_data.cleard_2 = is_Same(next_loc2,goal_info[1]);
						Q.push(new_data);
					}
				}
			}

			Q.pop();
		}
	}

	printf("%d\n",min_cost2[goal_info[0].row][goal_info[0].col][goal_info[1].row][goal_info[1].col]);
}

void calc1(){

	for(int a = 0; a < H; a++){
		for(int b = 0; b < W; b++){
			min_cost1[a][b] = BIG_NUM;
		}
	}

	priority_queue<Data> Q;
	min_cost1[start_info[0].row][start_info[0].col] = 0;
	Data first;
	first.total_cost = 0;
	first.loc_1 = start_info[0];
	first.cleard_1 = is_Same(start_info[0],goal_info[0]);
	Q.push(first);

	Info next_loc1;

	while(!Q.empty()){

		if(Q.top().cleard_1 == true){
			Q.pop();
		}else if(Q.top().total_cost > min_cost1[Q.top().loc_1.row][Q.top().loc_1.col]){
			Q.pop();
		}else{

			for(int i = 0; i < 5; i++){
				next_loc1.set(Q.top().loc_1.row+diff_row[i],Q.top().loc_1.col+diff_col[i]);
				if(table[next_loc1.row][next_loc1.col] == '#')continue;

				if(min_cost1[next_loc1.row][next_loc1.col] > Q.top().total_cost+1){
					min_cost1[next_loc1.row][next_loc1.col] = Q.top().total_cost+1;
					Data new_data;
					new_data.loc_1 = next_loc1;
					new_data.total_cost = Q.top().total_cost+1;
					new_data.cleard_1 = is_Same(next_loc1,goal_info[0]);
					Q.push(new_data);
				}
			}
			Q.pop();
		}
	}
	printf("%d\n",min_cost1[goal_info[0].row][goal_info[0].col]);
}


void func(){

	for(int row = 0; row < H; row++){

		getline(cin,line);
		for(int col = 0; col < W; col++)table[row][col] = line[col];

		for(int col = 0; col < W; col++){
			switch(table[row][col]){
			case 'a':
				start_info[0].set(row,col);
				break;
			case 'b':
				start_info[1].set(row,col);
				break;
			case 'c':
				start_info[2].set(row,col);
				break;
			case 'A':
				goal_info[0].set(row,col);
				break;
			case 'B':
				goal_info[1].set(row,col);
				break;
			case 'C':
				goal_info[2].set(row,col);
				break;
			}
		}
	}

	switch(N){
	case 1:
		calc1();
		break;
	case 2:
		calc2();
		break;
	case 3:
		calc3();
		break;
	}
}


int main(){

	while(true){
		scanf("%d %d %d",&W,&H,&N);
		if(W == 0 && H == 0 && N == 0)break;

		getchar();
		func();
	}

	return 0;
}

Measured memory_bytes: 52396