题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1044
题目大意:迷宫用一个二维数组表示,'@'表示起点,'*'表示障碍物不能到达,'.'表示路径,'<'表示终点,’A'~'J'表示宝石,宝石的价值之前输入。每一秒只能上下左右移动一步。求在规定时间限制内可以走出迷宫,拿到的最大的宝石价值。注意这道题每个位置是可以反复通过的。
我一开始的思路是纯粹的DFS求解,每个位置最多到达3次,设定一个数组记录到达各个位置的次数。如果当前时间超过规定时间以后return。由于限制时间很大,并且所有位置可以反复经过,所以会有大量的DFS,一定会超时。
后来看了一些解答以后大致了解了一下解题思路:
例如我们一共有2个宝石,标号为1,2。将起点标号为0,将终点标号为3。我们首先求出任意两个元素彼此之间的最短路径:
例如shortest_path[0][2]表示从起点0到终点2的最短路径。
这样可以用DFS求解(任意一步都是二者之间的最短路径):
0->1->2->3,0->1->3,0->2->1->3这样一步一步的DFS求解收集宝石最大价值,如果期间超过了限定时间,则返回即可。这里每一步DFS深入都是二者之间的最短路径,所以不用考虑每个位置可以重复经过的问题。
那么任意两个元素之间的最短路径怎么求解?用BFS求解就好。
例如这样的一个迷宫:
@.A.B
**<**
首先以@为起点,记step[i][j]为从起点到达(i,j)的最短路径。初始step[0][0]=0
邻近的(0,1)点入队列。step[0][1]=step[0][0]+1=1
队首元素出队列,队首元素邻近的(0,2)元素入队列,step[0][2]=step[0][1]+1=2,shortest[0][2]=2
队首元素(0,2)出队列,邻近的(1,2)入队列step[1][2]=step[0][2]+1=3,shortest[1][2]=3,邻近的(0,3)入队列step[0][3]=step[0][2]+1=3。
队首元素(1,2)出队列,无邻近元素
队首(0,3)出队列,邻近元素(0,4)入队列,step[0][4]=step[0][3]+1=4。
队首元素出队列,无邻近元素。队列为空,结束。
同样的以A为起点可以求出A到其他元素的最短路径。
我的求解:
#include
#include
#include
using namespace std;
/*
一共M个宝石,编号从1-M
起点为0,终点为M+1
*/
const int direct[4][2]={
{-1,0},{1,0},{0,-1},{0,1}
};
void bfs(int i,int j,int index);
void dfs(int index,int time,int total_value);
bool accessable(int x,int y);
char point[55][55];
int shortest_path[15][15];//shortest_path[i][j]:i到j的最短路径长度
bool visited[55][55];//标识是否到达过
int dfs_times[15];//dfs过程中,i到达的次数
int T;
int W,H,L,M;//W:长、H:宽、L:时间限制、M:宝石数量
int jewels[15];
int max_value=-1;//规定时间内能够拿到的最大价值
int sum_value=0;//所有宝石的总价值
int main(){
scanf("%d",&T);
int _case=1;
for(_case=1;_case<=T;_case++){
scanf("%d%d%d%d",&W,&H,&L,&M);
sum_value=0;
for(int i=0;i='A'&&point[i][j]<='J'){
bfs(i,j,point[i][j]-'A'+1);
}
}
}
/*
cout<<"bfs result:"<