#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
#include<set>
#include<deque>
#include<algorithm>
#include<cassert>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define MAX 17
using namespace std;

typedef pair<int,int> ii;

int h,w,n;
char G[MAX][MAX];
//unsigned char ev[MAX*MAX][MAX*MAX];
//unsigned char mincost[MAX*MAX][MAX*MAX][MAX*MAX];
short ev[MAX*MAX][MAX*MAX];
short mincost[MAX*MAX][MAX*MAX][MAX*MAX];
int dx[] = {0,1,0,-1,0};
int dy[] = {1,0,-1,0,0};
int goal[3],sp[3];
char cc[3];

struct Pox
{
  int cur[3];
  //unsigned char cost;
  short cost;
  Pox(int a=255,int b=255,int c=255,/*unsigned char*/short cost=1000/*255*/):cost(cost)
  {
    cur[0] = a, cur[1] = b, cur[2] = c;
  }
  bool operator < (const Pox &a)const
  {
    return cost > a.cost;
  }
};

void print(char a[MAX][MAX])
{
  rep(i,h)
    {
      rep(j,w)cout << a[i][j];
      cout << endl;
    }
  cout << endl;
}

bool isValidMove(int p11,int p12,int p21,int p22)
{
  if(p12 == p22)return false;//visited same point
  if(p12 == p21 && p11 == p22)return false;//cross

  return true;
}


void initEv()
{
  rep(y,h*w)rep(x,h*w)ev[y][x] = 1000;//255;
  rep(y,h)rep(x,w)
    {
      deque<ii> deq;
      deq.push_back(ii(x+y*w,0));
      ev[x+y*w][x+y*w] = 0;
      while(!deq.empty())
	{
	  ii state = deq.front(); deq.pop_front();
	  int cx = state.first % w;
	  int cy = state.first / w;
	  rep(i,4)
	    {
	      int nx = cx + dx[i];
	      int ny = cy + dy[i];
	      if(!(0 <= nx && nx < w && 0 <= ny && ny < h))continue;
	      if(G[ny][nx] == '#')continue;
	      if(ev[x+y*w][nx+ny*w] > state.second + 1)
		{
		  ev[x+y*w][nx+ny*w] = state.second + 1;
		  deq.push_back(ii(nx+ny*w,state.second+1));
		}
	    }
	}
    }
}

bool fin_check(int *cur)
{
  rep(i,n)if(cur[i] != goal[i])return false;
  return true;
}

void compute()
{
  /*
  rep(i,n)
    {
      cout << "goal[" << i << "] = " << goal[i] % w << "," << goal[i] / w << endl;
    }
  */
  rep(i,MAX*MAX)rep(j,MAX*MAX)rep(k,MAX*MAX)mincost[i][j][k] = 1000;//(unsigned char)255;

  priority_queue<Pox> Q;
  mincost[sp[0]][sp[1]][sp[2]] = 1000;//(unsigned char)0;
  Q.push(Pox(sp[0],sp[1],sp[2],0));

  while(!Q.empty())
    {
      Pox pox = Q.top(); Q.pop();

      //      cout << "pox ( ( " << pox.cur[0] << " " << pox.cur[0] % w << "," << pox.cur[0] / w << ") ( " << pox.cur[1] % w << "," << pox.cur[1] / w << " ) ) : " << (int)pox.cost << " \n"; 

      if(fin_check(pox.cur))
	{
	  cout << (int)pox.cost << endl;
	  return;
	}


      if(n == 1)
	{
	  int x = pox.cur[0] % w;
	  int y = pox.cur[0] / w;
	  rep(i,5)
	    {
	      int nx = x + dx[i];
	      int ny = y + dy[i];
	      if(!( 0 <= nx && nx < w && 0 <= ny && ny < h ))continue;
	      if(G[ny][nx] == '#')continue;

	      //cout << "mincost[" << pox.cur[0] << "][0][0] = " << (int)mincost[pox.cur[0]][0][0] << " > " << (pox.cost + 1) << endl;

	      if(mincost[nx+ny*w][0][0] > /*(unsigned char)*/(pox.cost + 1))
		{
		  mincost[nx+ny*w][0][0] = pox.cost + 1;
		  Pox next = Pox(nx+ny*w,0,0,pox.cost+1);
		  Q.push(next);
		}
	    }
	}
      else if(n == 2)
	{
	  int x1 = pox.cur[0] % w;
	  int y1 = pox.cur[0] / w;
	  int x2 = pox.cur[1] % w;
	  int y2 = pox.cur[1] / w;

	  rep(i,5)
	    {
	      int nx1 = x1 + dx[i];
	      int ny1 = y1 + dy[i];
	      if(!( 0 <= nx1 && nx1 < w && 0 <= ny1 && ny1 < h ))continue;
	      if(G[ny1][nx1] == '#')continue;

	      rep(j,5)
		{
		  int nx2 = x2 + dx[j];
		  int ny2 = y2 + dy[j];
		  if(!( 0 <= nx2 && nx2 < w && 0 <= ny2 && ny2 < h ))continue;
		  if(G[ny2][nx2] == '#')continue;
		  if(!isValidMove(pox.cur[0],nx1+ny1*w,pox.cur[1],nx2+ny2*w))continue;
		  //cout << "here : " << (int)mincost[nx1+ny1*w][nx2+ny2*w][0] << " > " << pox.cost + 1 << endl;

		  if(mincost[nx1+ny1*w][nx2+ny2*w][0] > /*(unsigned char)*/(pox.cost + 1))
		    {
		      mincost[nx1+ny1*w][nx2+ny2*w][0] = pox.cost + 1;
		      Q.push(Pox(nx1+ny1*w,nx2+ny2*w,0,pox.cost+1));
		    }
		}
	    }
	}
      else if(n == 3)
	{

	  int x[3],y[3],nx[3],ny[3];
	  rep(i,3)x[i] = pox.cur[i] % w, y[i] = pox.cur[i] / w;

	  rep(i,5)
	    {
	      nx[0] = x[0] + dx[i];
	      ny[0] = y[0] + dy[i];
	      if(!( 0 <= nx[0] && nx[0] < w && 0 <= ny[0] && ny[0] < h ))continue;
	      if(G[ny[0]][nx[0]] == '#')continue;

	      rep(j,5)
		{
		  nx[1] = x[1] + dx[j];
		  ny[1] = y[1] + dy[j];
		  if(!( 0 <= nx[1] && nx[1] < w && 0 <= ny[1] && ny[1] < h ))continue;
		  if(G[ny[1]][nx[1]] == '#')continue;
		  if(!isValidMove(pox.cur[0],nx[0]+ny[0]*w,pox.cur[1],nx[1]+ny[1]*w))continue;

		  rep(k,5)
		    {
		      nx[2] = x[2] + dx[k];
		      ny[2] = y[2] + dy[k];
		      if(!( 0 <= nx[2] && nx[2] < w && 0 <= ny[2] && ny[2] < h ))continue;
		      if(G[ny[2]][nx[2]] == '#')continue;
		      if(!isValidMove(pox.cur[0],nx[0]+ny[0]*w,pox.cur[2],nx[2]+ny[2]*w))continue;
		      if(!isValidMove(pox.cur[1],nx[1]+ny[1]*w,pox.cur[2],nx[2]+ny[2]*w))continue;

		      if(mincost[nx[0]+ny[0]*w][nx[1]+ny[1]*w][nx[2]+ny[2]*w] > /*(unsigned char)*/(pox.cost + 1))
			{
			  mincost[nx[0]+ny[0]*w][nx[1]+ny[1]*w][nx[2]+ny[2]*w] = pox.cost + 1;
			  Q.push(Pox(nx[0]+ny[0]*w,nx[1]+ny[1]*w,nx[2]+ny[2]*w,pox.cost+1));
			}
		    }
		}
	    }
	}
    }
  assert(false);
}

int main()
{
  while(scanf("%d %d %d",&w,&h,&n),h|w|n)
    {
      rep(i,3)sp[i] = 0;
      int cd = 0;
      map<char,int> dex;
      rep(i,h)
	{
	  getchar();
	  rep(j,w)
	    {
	      scanf("%c",&G[i][j]);
	      dex[G[i][j]] = j + i * w;
	      if('a' <= G[i][j] && G[i][j] <= 'z')
		{
		  sp[cd] = j + i * w;
		  cc[cd++] = G[i][j];
		}
	    }
	}
      assert(n == cd);
      rep(i,n)goal[i] = dex['A'+cc[i]-'a'];

      //print(G);
      initEv();

      compute();


    }
  return 0;
}

Measured memory_bytes: 58556