//hdu 1044 Collect More Jewels
//搜索
//题意:起点 '@' 终点 '<' 宝石 'A' ~ 'J',在一定时间内
//从起点到终点,且求出能得到最多价值是多少
//思路:先用广搜求出起点、终点即所有宝石之间的最短距离
//然后深搜
#include <stdio.h>
#include <string.h>
#define N 55
#define INF 1<<30
#define eps 1e-5
const int dir[2][4] = {0, -1, 0, 1, -1, 0, 1, 0};
struct NODE
{
int x, y;
}node[20], que[N*N];
int col, row, limit, n_jewel, ans;
int jewel[15], step[N][N]; //step记录广搜中到某个结点的步数
int dis[20][20];
char map[N][N];
bool vis[20];
bool no_overmap(int x, int y)
{
return (x >= 0 && x < col && y >= 0 && y < row);
}
int get_index(int x, int y)
{
if(map[x][y] == '@')
return n_jewel + 1;
else if(map[x][y] == '<')
return n_jewel;
else
return map[x][y] - 'A';
}
void bfs(int root) //breadth first search
{
for(int i = 0; i < col; ++i)
for(int j = 0; j < row; ++j)
step[i][j] = 0;
int head = 0, tail = 0;
que[++head].x = node[root].x;
que[head].y = node[root].y;
while(tail < head)
{
int x = que[++tail].x, y = que[tail].y;
for(int i = 0; i < 4; ++i)
{
int nx = x + dir[0][i], ny = y + dir[1][i];
if(no_overmap(nx, ny) && step[nx][ny] == 0 && map[nx][ny] != '*' &&
(nx != node[root].x || ny != node[root].y))
{
step[nx][ny] = step[x][y] + 1;
if(map[nx][ny] != '.')
{
int to = get_index(nx, ny);
dis[root][to] = step[nx][ny];
}
que[++head].x = nx;
que[head].y = ny;
}
}
}
}
void dfs(int root, int val, int time)
{
//记得判断当前点即root到终点的时间,否则超时,有的话也要900多毫秒才过
if(time + dis[root][n_jewel] > limit)
return;
if(root == n_jewel)
{
ans = ans > val ? ans : val;
return;
}
//由于最短路之前都求过了,dfs只要判断该点要或不要就可以了
//则列举这些点的排列肯定有一种是答案,当前点可以要或不要
for(int i = 0; i <= n_jewel; ++i)
{
if(vis[i] == false && time + dis[root][i] <= limit)
{
vis[i] = true;
dfs(i, val + jewel[i], time + dis[root][i]);
vis[i] = false;
}
}
}
int main()
{
freopen("in.txt", "r", stdin);
int n_case;
scanf("%d", &n_case);
for(int ca = 1; ca <= n_case; ++ca)
{
printf("Case %d:\n", ca);
scanf("%d%d%d%d", &row, &col, &limit, &n_jewel);
for(int i = 0; i < n_jewel; ++i)
scanf("%d", &jewel[i]);
for(int i = 0; i < col; ++i)
{
getchar();
for(int j = 0; j < row; ++j)
{
map[i][j] = getchar();
if(map[i][j] == '@')
{
node[n_jewel + 1].x = i;
node[n_jewel + 1].y = j;
jewel[n_jewel + 1] = 0;
}
if(map[i][j] == '<')
{
node[n_jewel].x = i;
node[n_jewel].y = j;
jewel[n_jewel] = 0;
}
if(map[i][j] >= 'A' && map[i][j] <= 'J')
{
node[map[i][j] - 'A'].x = i;
node[map[i][j] - 'A'].y = j;
}
}
}
for(int i = 0; i <= n_jewel + 1; ++i)
for(int j = 0; j < i; ++j)
dis[i][j] = dis[j][i] = INF;
bfs(n_jewel + 1);
if(dis[n_jewel + 1][n_jewel] > limit)
{
printf("Impossible\n\n");
continue;
}
for(int i = 0; i <= n_jewel; ++i) //求i到各点的最短距离
bfs(i);
for(int i = 0; i <= n_jewel + 1; ++i)
vis[i] = false;
ans = 0;
dfs(n_jewel + 1, 0, 0);
printf("The best score is %d.\n", ans);
if(ca != n_case)
puts("");
}
return 0;
}