/*本题用到状态压缩,这个还真没想到,想到了也不会。。
得好好学学状态压缩了;
本题要采用|运算来模拟拾取钥匙点;(用<<左移合并);
用&来判断是否能打开该门; (>>右移&1来判断);
100表示有第3把,111表示有第3,2,1把钥匙,如果该点为钥匙点,则可采用|运算来模拟拾取,
显然0001|1000 = 1001,同理,当为相应的门时采用&运算来模拟开启,
例如1101 & 0001 = 0001(即可以打开'A'门)*/
#include"stdio.h"
#include"string.h"
#include"queue"
using namespace std;
char map[21][21];
int visit[21][21][1<<10];
int dir[4][2]={-1,0, 0,1, 1,0, 0,-1};
int n,m,k,sx,sy,ex,ey;
struct point
{
int x,y,z;
int step;
};
int judge(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<m&&map[x][y]!='*')
return 1;
return 0;
}
int bfs(int x,int y)
{
int i,p;
memset(visit,0,sizeof(visit));
queue<point>q;
point cur,next;
cur.x=x;cur.y=y;cur.step=0;cur.z=0;
visit[x][y][0]=1;
q.push(cur);
while(!q.empty())
{
next=q.front();
q.pop();
if(next.step>=k)
return -1;
if(next.x==ex&&next.y==ey&&next.step<k)
return next.step;
for(i=0;i<4;i++)
{
cur.x=x=next.x+dir[i][0];
cur.y=y=next.y+dir[i][1];
cur.step=next.step+1;
cur.z=next.z;
if(judge(x,y))
{
if(map[x][y]>='a'&&map[x][y]<='j')
{
p=(1<<(map[x][y]-'a')); //<<左移运算符 ,例map[][]为'b',则左移1位,变10 ;
cur.z=(cur.z|p);//把p放进去;
if(visit[x][y][cur.z]==0)
{
visit[x][y][cur.z]=1;
q.push(cur);
}
}
else if(map[x][y]>='A'&&map[x][y]<='J')
{
p=(cur.z>>(map[x][y]-'A'));//>>右移运算符 ,若next=1010,右移一位变为101,
//101&1!=0即可以开门
if((p&1)&&!visit[x][y][cur.z])
{
visit[x][y][cur.z]=1;
q.push(cur);
}
}
else if(!visit[x][y][cur.z])
{
visit[x][y][cur.z]=1;
q.push(cur);
}
}
}
}
return -1;
}
int main()
{
int i,j;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%s",map[i]);
for(j=0;j<m;j++)
{
if(map[i][j]=='@')
{
sx=i;sy=j;
}
if(map[i][j]=='^')
{
ex=i;ey=j;
}
}
}
printf("%d\n",bfs(sx,sy));
}
return 0;
}