Problem:
Problem F: Mysterious Dungeons

The Kingdom of Aqua Canora Mystica is a very affluent and peaceful country, but around the
kingdom, there are many evil monsters that kill people. So the king gave an order to you to kill
the master monster.

You came to the dungeon where the monster lived. The dungeon consists of a grid of square
cells. You explored the dungeon moving up, down, left and right. You finally found, fought
against, and killed the monster.

Now, you are going to get out of the dungeon and return home. However, you found strange
carpets and big rocks are placed in the dungeon, which were not there until you killed the
monster. They are caused by the final magic the monster cast just before its death! Every rock
occupies one whole cell, and you cannot go through that cell. Also, each carpet covers exactly
one cell. Each rock is labeled by an uppercase letter and each carpet by a lowercase. Some of
the rocks and carpets may have the same label.

While going around in the dungeon, you observed the following behaviors. When you enter
into the cell covered by a carpet, all the rocks labeled with the corresponding letter (e.g., the
rocks with ‘A’ for the carpets with ‘a’) disappear. After the disappearance, you can enter the
cells where the rocks disappeared, but if you enter the same carpet cell again or another carpet
cell with the same label, the rocks revive and prevent your entrance again. After the revival,
you have to move on the corresponding carpet cell again in order to have those rocks disappear
again.

Can you exit from the dungeon? If you can, how quickly can you exit? Your task is to write
a program that determines whether you can exit the dungeon, and computes the minimum
required time.

Input

The input consists of some data sets.

Each data set begins with a line containing two integers, W and H (3 ≤ W, H ≤ 30). In each
of the following H lines, there are W characters, describing the map of the dungeon as W × H
grid of square cells. Each character is one of the following:

‘@’ denoting your current position,

‘<’ denoting the exit of the dungeon,

A lowercase letter denoting a cell covered by a carpet with the label of that letter,

An uppercase letter denoting a cell occupied by a rock with the label of that letter,

‘#’ denoting a wall, and

‘.’ denoting an empty cell.

Every dungeon is surrounded by wall cells (‘#’), and has exactly one ‘@’ cell and one ‘<’ cell.
There can be up to eight distinct uppercase labels for the rocks and eight distinct lowercase
labels for the carpets.

You can move to one of adjacent cells (up, down, left, or right) in one second. You cannot move
to wall cells or the rock cells.

A line containing two zeros indicates the end of the input, and should not be processed.

Output

For each data set, output the minimum time required to move from the ‘@’ cell to the ‘<’ cell,
in seconds, in one line. If you cannot exit, output -1.

Sample Input

8 3
########
#<A.@.a#
########
8 3
########
#<AaAa@#
########
8 4
########
#<EeEe@#
#FG.e#.#
########
8 8
########
#mmm@ZZ#
#mAAAbZ#
#mABBBZ#
#mABCCd#
#aABCDD#
#ZZcCD<#
########
0 0

Output for the Sample Input

7
-1
7
27

Solution in C (judge verdict: Accepted)

// AOJ 2089 Mysterious Dungeons
// 2018.3.24 bal4u

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define QMAX  230500
typedef unsigned char uchar;
typedef struct { char r, c; uchar s; int t; } Q;
Q q[QMAX+2]; int top, end;
short mk[31][31][1<<8];
char map[33][33];
char f['z'+1], id['z'+1]; int sz;
int  mv[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};

int main()
{
	int W, H, i, r, c, nr, nc, t, s, ns, a, ans;
	int sr, sc, gr, gc;
	char buf[10], *p;
	
	while (fgets(p=buf, 10, stdin) && *p != '0') {
		sscanf(p, "%d%d", &W, &H);
		sz = 0; memset(f, 0, sizeof(f)), memset(id, 0, sizeof(id));
		for (r = 0; r < H; r++) {
			fgets(p=map[r], 33, stdin);
			for (c = 0; c < W; c++) {
				if      (*p == '@') sr = r, sc = c, *p = '.';
				else if (*p == '<') gr = r, gc = c, *p = '.';
				else if (islower(*p)) f[*p] |= 1, f[toupper(*p)] |= 1;
				else if (isupper(*p)) f[*p] |= 2, f[tolower(*p)] |= 2;
				p++;
			}
		}
		for (r = 0; r < H; r++) {
			for (p = map[r], c = 0; c < W; c++) {
				if (islower(*p)) {
					if (f[*p] != 3) *p = '.';
					else {
						if (!id[*p]) id[*p] = (sz<<2)|1, id[toupper(*p)] = ((sz++)<<2)|3;
						*p = id[*p]>>1;
					}
				} else if (isupper(*p)) {
					if (f[*p] != 3) *p = '#';
					else {
						if (!id[*p]) id[*p] = (sz<<2)|3, id[tolower(*p)] = ((sz++)<<2)|1;
						*p = id[*p]>>1;
					}
				}
				p++;
			}
		}

		memset(mk, 0x55, sizeof(mk));
		q[0].r = sr, q[0].c = sc, q[0].t = 0, q[0].s = 0, mk[sr][sc][0] = 0;
		top = 0, end = 1, ans = -1;
		while (top != end) {
			r = q[top].r, c = q[top].c, t = q[top].t, s = q[top++].s;

			if (r == gr && c == gc) { ans = t; break; }
			if (mk[r][c][s] < t) continue;

			for (i = 0; i < 4; i++) {
				nr = r + mv[i][0], nc = c + mv[i][1], ns = s;
				if (map[nr][nc] == '#') continue;
				if ((a = map[nr][nc]) < 32) {
					if (a & 1) { if (!(s & (1<<(a>>1)))) continue; }
					else ns = s ^ (1<<(a>>1));
				}
				if (mk[nr][nc][ns] > t+1) {
					mk[nr][nc][ns] = t+1;
					q[end].r = nr, q[end].c = nc, q[end].t = t+1, q[end++].s = ns;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}