Language: C++

// forked from http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=1587939#1
#include <iostream>
#include <array>
#include <vector>
#include <cctype>
#include <unordered_set>
#include <queue>
#include <algorithm>
#include <cassert>
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
#define repeat_reverse(i,n) for (int i = (n)-1; (i) >= 0; --(i))
#define repeat_from_reverse(i,m,n) for (int i = (n)-1; (i) >= (m); --(i))
#define dump(x)  cerr << #x << " = " << (x) << endl
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl
typedef long long ll;
using namespace std;
 
struct point_t {
    int y, x;
};
point_t operator + (point_t const & a, point_t const & b) {
    return (point_t){ a.y + b.y, a.x + b.x };
}
bool operator == (point_t const & a, point_t const & b) {
    return make_pair(a.y, a.x) == make_pair(b.y, b.x);
}
bool operator < (point_t const & a, point_t const & b) {
    return make_pair(a.y, a.x) < make_pair(b.y, b.x);
}
static point_t dp[5] = { {-1,0}, {1,0}, {0,1}, {0,-1}, {0,0} };
 
array<point_t,3> start, goal;
int dist(const array<point_t, 3>& s, const array<point_t, 3>& t) {
    int r = 0;
    for (int i = 0; i < 3; i++) {
        r += abs(s[i].x - t[i].x);
        r += abs(s[i].y - t[i].y);
    }
    return r;
}
struct state_t {
    array<point_t,3> a;
    int cost;
    bool operator<(const state_t& s) const {
        if (cost == s.cost) {
            return dist(a, goal) > dist(s.a, goal);
        } else {
            return cost > s.cost;
        }
    }
};
uint32_t encode(array<point_t,3> const & s) {
    uint32_t q = 0;
    for (point_t p : s) {
        q = (q * 18) + p.y;
        q = (q * 16) + p.x;
    }
    return q;
}
bool is_valid_move(int i, int j, array<point_t,3> const & s, array<point_t,3> const & t) {
    if (t[i] == t[j]) return false;
    if (t[i] == s[j] and t[j] == s[i]) return false;
    return true;
}
 
int main() {
    while (true) {
        int w, h, n; cin >> w >> h >> n; cin.ignore();
        if (w == 0 and h == 0 and n == 0) break;
        vector<string> c(h);
        repeat (i,h) getline(cin, c[i]);
 
        assert (1 <= n and n <= 3);
        //array<point_t,3> start, goal;
        repeat (y,h) repeat (x,w) {
            if (islower(c[y][x])) {
                start[c[y][x] - 'a'] = { y, x };
            } else if (isupper(c[y][x])) {
                goal[c[y][x] - 'A'] = { y, x };
            }
        }
        if (n == 1 or n == 2) {
            assert (4 <= w);
            string w = c.back();
            c.push_back(w);
            c.back()[2] = '.';
            start[2] = goal[2] = (point_t){ h, 2 };
            if (n == 1) {
                c.back()[1] = '.';
                start[1] = goal[1] = (point_t){ h, 1 };
            }
            c.push_back(w);
            h += 2;
        }
 
        unordered_set<uint32_t> used;
        priority_queue<state_t> que; {
            state_t initial = { start, 0 };
            used.insert(encode(start));
            que.push(initial);
        }
        while (not que.empty()) {
            state_t st = que.top(); que.pop();
            array<point_t,3> & s = st.a;
            if (s == goal) {
                cout << st.cost << endl;
                break;
            }
            state_t tt = st;
            tt.cost += 1;
            array<point_t,3> & t = tt.a;
            repeat (i,5) { // a
                t[0] = s[0] + dp[i];
                if (c[t[0].y][t[0].x] == '#') continue;
                repeat (j,5) { // b
                    t[1] = s[1] + dp[j];
                    if (c[t[1].y][t[1].x] == '#') continue;
                    if (not is_valid_move(0, 1, s, t)) continue;
                    repeat (k,5) { // c
                        t[2] = s[2] + dp[k];
                        if (c[t[2].y][t[2].x] == '#') continue;
                        if (not is_valid_move(1, 2, s, t)) continue;
                        if (not is_valid_move(2, 0, s, t)) continue;
                        if (used.count(encode(t))) continue;
                        used.insert(encode(t));
                        que.push(tt);
                    }
                }
            }
        }
    }
    return 0;
}

Compiler output:
a.cc:53:1: error: 'uint32_t' does not name a type
   53 | uint32_t encode(array<point_t,3> const & s) {
      | ^~~~~~~~
a.cc:10:1: note: 'uint32_t' is defined in header '<cstdint>'; this is probably fixable by adding '#include <cstdint>'
    9 | #include <cassert>
  +++ |+#include <cstdint>
   10 | #define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
a.cc: In function 'int main()':
a.cc:97:23: error: 'uint32_t' was not declared in this scope
   97 |         unordered_set<uint32_t> used;
      |                       ^~~~~~~~
a.cc:97:23: note: 'uint32_t' is defined in header '<cstdint>'; this is probably fixable by adding '#include <cstdint>'
a.cc:97:31: error: template argument 1 is invalid
   97 |         unordered_set<uint32_t> used;
      |                               ^
a.cc:97:31: error: template argument 2 is invalid
a.cc:97:31: error: template argument 3 is invalid
a.cc:97:31: error: template argument 4 is invalid
a.cc:100:18: error: request for member 'insert' in 'used', which is of non-class type 'int'
  100 |             used.insert(encode(start));
      |                  ^~~~~~
a.cc:100:25: error: 'encode' was not declared in this scope
  100 |             used.insert(encode(start));
      |                         ^~~~~~
a.cc:125:34: error: request for member 'count' in 'used', which is of non-class type 'int'
  125 |                         if (used.count(encode(t))) continue;
      |                                  ^~~~~
a.cc:125:40: error: 'encode' was not declared in this scope
  125 |                         if (used.count(encode(t))) continue;
      |                                        ^~~~~~
a.cc:126:30: error: request for member 'insert' in 'used', which is of non-class type 'int'
  126 |                         used.insert(encode(t));
      |                              ^~~~~~
a.cc:126:37: error: 'encode' was not declared in this scope
  126 |                         used.insert(encode(t));
      |                                     ^~~~~~