题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1044
此题系BFS和DFS的结合使用,需要理解BFS和DFS的特点。
BFS:对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费较大,需要开辟大量的数组单元来存储状态。
DFS:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理迅速,然而在深度很大的情况下效率不高。
问题:在能够走出迷宫的前提下,如何尽可能多(价值之和大)的收集珠宝?
分析:
1、从题目可知,珠宝的数目及每个珠宝的价值我们能够知道,要求“最多”,我们通常会联想到动态规划。但从题目本身看,我们很难看到动态规划的影子。于是我们可以考虑构造动态规划的条件。
2、于是就有了这样的Idea:用BFS,先将“起始点--珠宝”、“珠宝--珠宝”、“珠宝—出口”两两间的最短距离求出来,构造一个新的图,用marix存储,matrix的每个元素即两个点之间的最短距离。
3、然后我们就可以利用动态规划(即这里的DFS)来求满足条件(能够走出迷宫;收集价值量最大的珠宝)的最优路径。
#include<iostream> #include<queue> #include<ctype.h> #include<string.h> using namespace std; int T, W, H, M, L; char dungeon[60][60]; int newMap[60][60]; int value[60]; int totalValue; int dis[60][60]; int visited1[60][60]; int visited2[60]; int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; int res; typedef struct{ int x; int y; }Pos; queue<Pos> que; void bfs(int y, int x, int p) { int i; while(!que.empty()){ que.pop(); } Pos cur; cur.x = x; cur.y = y; visited1[y][x] = 1; dis[y][x] = 0; que.push(cur); while(!que.empty()){ cur = que.front(); que.pop(); for(i=0; i<4; i++){ Pos next; next.y = cur.y + dir[i][0]; next.x = cur.x + dir[i][1]; if(next.y>=H || next.y<0 || next.x>=W || next.x<0){ continue; } if(visited1[next.y][next.x]==0 && dungeon[next.y][next.x]!='*'){ visited1[next.y][next.x] = 1; dis[next.y][next.x] = dis[cur.y][cur.x] + 1; if(dungeon[next.y][next.x] == '@'){ newMap[p][0] = dis[next.y][next.x]; } if(isalpha(dungeon[next.y][next.x])){ newMap[p][dungeon[next.y][next.x]-64] = dis[next.y][next.x]; } if(dungeon[next.y][next.x] == '<'){ newMap[p][M+1] = dis[next.y][next.x]; } que.push(next); } } } } void dfs(int p, int v, int time) { if(time>L || res==totalValue){ return ; } if(p>M && v>res){ //p=M+1说明能够走出去,当v>res时更新res res = v; } for(int i=0; i<=M+1; i++){ if(newMap[p][i]==0 || visited2[i]){ continue; } visited2[i] = 1; dfs(i, v+value[i], time+newMap[p][i]); visited2[i] = 0; } } int main() { int i, j, k, x; scanf("%d", &T); x = 1; while(T--){ memset(visited2, 0, sizeof(visited2)); memset(value, 0, sizeof(value)); memset(newMap, 0, sizeof(newMap)); scanf("%d%d%d%d", &W, &H, &L, &M); totalValue = 0; //totalValue是一个剪枝条件,不考虑会超时 for(j=1; j<=M; j++){ scanf("%d", &value[j]); totalValue += value[j]; } value[0] = value[M+1] = 0; for(j=0; j<H; j++){ scanf("%s", dungeon[j]); } for(i=0; i<H; i++){ for(j=0; j<W; j++){ memset(visited1, 0, sizeof(visited1)); memset(dis, 0, sizeof(dis)); if(dungeon[i][j]=='@'){ bfs(i, j, 0); } if(isalpha(dungeon[i][j])){ bfs(i, j, dungeon[i][j]-64); } if(dungeon[i][j] == '<'){ bfs(i, j, M+1); } } } res = -1; visited2[0] = 1; dfs(0, 0, 0); printf("Case %d:\n", x++); if(res >= 0){ printf("The best score is %d.\n", res); } else{ printf("Impossible\n"); } if(T){ printf("\n"); } } }