代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxw = 20;
const int dx[5] = {0, 0, 0,-1, 1};
const int dy[5] = {0,-1, 1, 0, 0};
int w, h, n;
char a[maxw][maxw];
int targx[3];
int targy[3];
struct State { //一个状态
int x[3] = {}, y[3] = {}; //3只鬼的位置
int d; //已经走了d步
void operator=(State st) { //复制状态
x[0] = st.x[0];
x[1] = st.x[1];
x[2] = st.x[2];
y[0] = st.y[0];
y[1] = st.y[1];
y[2] = st.y[2];
d = st.d;
}
};
set<ll> vis;
int state2num(State st) { //把一个状态转换成一个数
int ret = 0;
for(int i = 0; i < n; i++) {
ret = (ret << 4) + st.x[i] - 1;
}
for(int i = 0; i < n; i++) {
ret = (ret << 4) + st.y[i] - 1;
}
return ret;
}
void init() {
vis.clear(); //清空访问标记
}
void input(queue<State> &q) {
init();
int cnt = 0;
int ch2num[130];
memset(ch2num, -1, sizeof(ch2num));
State start;
for(int i = 1; i <= h; i++) {
fgets(a[i] + 1, 20, stdin);
for(int j = 1; j <= w; j++) {
char lowch = tolower(a[i][j]);
if(a[i][j] >= 'a' && a[i][j] <= 'z') { //遇到一只鬼
if(ch2num[lowch] != -1) { //未标记这只鬼
start.x[ch2num[lowch]] = i;
start.y[ch2num[lowch]] = j; //记录初始位置
} else {
ch2num[lowch] = cnt; //新增编号
start.x[cnt] = i;
start.y[cnt] = j; //记录初始位置
cnt++; //当前编号被用了,可用编号加1
}
} else if(a[i][j] >= 'A' && a[i][j] <= 'Z') { //遇到一只鬼的目标位置
if(ch2num[lowch] != -1) { //未标记这只鬼
targx[ch2num[lowch]] = i;
targy[ch2num[lowch]] = j; //记录目标位置
} else {
ch2num[lowch] = cnt; //新增编号
targx[cnt] = i;
targy[cnt] = j; //记录目标位置
cnt++; //当前编号被用了,可用编号加1
}
}
}
//getchar();
}
/*
for(int i = 0; i < n; i++) {
printf("targ %d: (%d, %d)\n", i, targx[i], targy[i]);
}
for(int i = 0; i < n; i++) {
printf("now %d: (%d, %d)\n", i, start.x[i], start.y[i]);
}
*/
start.d = 0;
vis.insert(state2num(start));
q.push(start);
}
bool check(State st) { //检查st是否是目标状态
for(int i = 0; i < n; i++) {
if(st.x[i] != targx[i] || st.y[i] != targy[i]) { //与目标状态不符
return false; //不是
}
}
return true; //是
}
void solve() {
//init
queue<State> q;
input(q); //输入+压入初始状态
//bfs
while(!q.empty()) {
State u = q.front(); //取队首状态
q.pop();
if(check(u)) { //到达目标状态
printf("%d\n", u.d);
return;
}
for(int i = 0; i < 5; i++) { //遍历每一个鬼的移动方向
for(int j = 0; j < 5; j++) {
for(int k = 0; k < 5; k++) {
if(i == 0 && j == 0 && k == 0) { //全都原地不动
continue;
}
State tmp = u;
tmp.x[0] += dx[i];
tmp.y[0] += dy[i];
tmp.x[1] += dx[j];
tmp.y[1] += dy[j];
tmp.x[2] += dx[k];
tmp.y[2] += dy[k]; //移动
tmp.d++; //步数加1
bool flag = false;
for(int i = 0; i < n; i++) {
if(a[tmp.x[i]][tmp.y[i]] == '#') { //遇到障碍物
// printf("0\n");
// printf("u: (%d, %d)\ntmp: (%d, %d)\nd: %d\n", u.x[i], u.y[i], tmp.x[i], tmp.y[i], tmp.d);
flag = true;
break;
// continue;
}
for(int j = i + 1; j < n; j++) {
if((tmp.x[i] == tmp.x[j] && tmp.y[i] == tmp.y[j]) || (tmp.x[i] == u.x[j] && tmp.y[i] == u.y[j] && tmp.x[j] == u.x[i] && tmp.y[j] == u.y[i])) { //两个鬼在同一位置或交换了位置
flag = true;
break;
}
}
if(flag) {
break;
// continue;
}
}
if(flag) { //非法移动
continue;
}
// bool flag = false;
// for(int i = 0; i < n; i++) {
// if(a[tmp.x[i]][tmp.y[i]] == '#') {
//// printf("0\n");
//// flag = true;
//// break;
// continue;
// }
// }
// if(flag) {
//// continue;
// }
int num = state2num(tmp);
if(!vis.count(num)) { //没有访问过这个状态
vis.insert(num); //标记访问
q.push(tmp); //入队
}
}
}
}
}
cout << "Error!" << endl;
}
int main() {
// freopen("..\\in.txt", "r", stdin);
// freopen("..\\out.txt", "w", stdout);
while(cin >> w >> h >> n && w != 0) { //输入
getchar();
solve();
}
}