题目链接:Collect More Jewels
解题思路:一看又是简单的广搜,还以为水题,所以简单敲了一发,T了。思佳说用BFS + DFS。算了算总状态数50*50*2^10 = 256W, 一共10组,而且还有它给出的时间有可能很多,这样所有宝物都能捡到还能瞎逛。就是宝物逝去序列的所有组合。所以应该先处理两两宝物之间的最短路,和起点到所有宝物的最短路,终点到所有宝物的最短路,全部用BFS跑一遍,然后再对所有宝物进行DFS找到最大的价值,要注意如果已经找到最大值就要直接退出,否则会TLE。减枝很重要。
#include<cstdio>
#include<cstring>
#include<queue>
#define MAX 55
#define MAXN 20
#define INF 0x5f5f5f5f
using namespace std;
struct node{
int x, y, s;
node(){}
node(int xx, int yy, int ss){
x = xx, y = yy, s = ss;
}
};
int n, m, l, k;
int g[MAX][MAX], dis[MAXN][MAXN];
bool v[MAX][MAX], vis[MAXN];
int jv[MAXN], jx[MAXN], jy[MAXN];
int ans, sx, sy, ex, ey, sum;
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
void init(){
for(int i = 0; i < k; i++){
for(int j = 0; j < k; j++){
dis[i][j] = i == j ? 0 : INF;
}
}
ans = -1;
memset(vis, 0, sizeof(vis));
}
int getC(char c){
if(c == '@') return 0;
if(c == '<') return k - 1;
if(c >= 'A' && c <= 'J') return c - 'A' + 1;
return -1;
}
void bfs(int x, int y, int idx){
int i, j;
queue<node> mq;
memset(v, false, sizeof(v));
v[x][y] = true;
mq.push(node(x, y, 0));
while(!mq.empty()){
node s = mq.front();
//printf("idx = %d %d %d %d\n", idx, s.x, s.y, s.s);
mq.pop();
for(i = 0; i < 4; i++){
int xx = s.x + dir[i][0];
int yy = s.y + dir[i][1];
int ss = s.s + 1;
if(xx >= 0 && xx < n && yy >= 0 && yy < m && !v[xx][yy] && g[xx][yy] != '*'){
v[xx][yy] = true;
if(getC(g[xx][yy]) != -1){
dis[getC(g[xx][yy])][idx] = ss;
dis[idx][getC(g[xx][yy])] = ss;
}
mq.push(node(xx, yy, ss));
}
}
}
}
void dfs(int now, int d, int v, int pre){
//printf("%d %d %d %d\n",pre, now, d, v);
int i, j;
if(d > l || sum == ans) return;
if(now == k - 1 && v > ans){
ans = v;
}
for(i = 0; i < k; i++){
if(dis[now][i] == INF || vis[i]) continue;
vis[i] = true;
dfs(i, d + dis[now][i], v + jv[i], now);
vis[i] = false;
}
}
int main(){
int i, j, t, tot = 0;
//#ifndef ONLINE_JUDGE
//freopen("1.in", "r", stdin);
//freopen("1.out", "w", stdout);
//#endif // ONLINE_JUDGE
scanf("%d", &t);
while(t--){
if(tot++) printf("\n");
scanf("%d%d%d%d", &m, &n, &l, &k);
sum = 0;
for(i = 1; i <= k; i++){
scanf("%d", &jv[i]);
sum += jv[i];
}
jv[0] = jv[k + 1] = 0;
k += 2;
init();
for(i = 0; i < n; i++){
getchar();
for(j = 0; j < m; j++){
g[i][j] = getchar();
if(g[i][j] == '@'){
jx[0] = i, jy[0] = j;
}
if(g[i][j] == '<'){
jx[k - 1] = i, jy[k - 1] = j;
}
if(g[i][j] <= 'J' && g[i][j] >= 'A'){
jx[g[i][j] + 1 - 'A'] = i;
jy[g[i][j] + 1 - 'A'] = j;
}
}
}
for(i = 0; i < k - 1; i++){
bfs(jx[i], jy[i], i);
}
printf("Case %d:\n", tot);
if(dis[0][k - 1] > l){
puts("Impossible");
continue;
}
vis[0] = true;
dfs(0, 0, 0, -1);
if(ans == -1){
puts("Impossible");
}
else{
printf("The best score is %d.\n", ans);
}
}
return 0;
}