题目要求
已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?
输入
输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。
样例输入1
4 4 1
#@##
**##
###+
****
样例输入2
4 4 2
#@##
**##
###+
****
输出
输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。
样例输出1
6
样例输出2
4
题目分析
这道题在DFS时把查克拉T作为一个参数会更加方便,然后把#和*分开来判断,遍历上下左右四种走法,DFS走完后记得回溯,也就是把访问置为未访问、加上的时间减回去。
此外,这道题需要剪枝操作,否则会超时。跟老师讲的一样,使用两个最优性剪枝:
1.走到这一步的时间已经超过了目前记录的最短时间,自然也就没必要走下去了,return。
2.记录走到每个点时,花费的不同查克拉情况下的时间。如果花费查克拉相等时,现在比以前花的时间长,那也没必要走下去了,return。
记得在DFS里包含起点@的情况,否则无法进入递归循环。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int M, N, T;
int flag = 0; //标记是否走到了终点
int mintime;
int totaltime;
char all[210][210]; //原始数组
int visited[210][210]; //标记是否访问过
int minl[210][210][11]; //minl[m][n][t] 表示走到m,n这个点时还有t查克拉情况下的最小时间
void dfs(int m, int n, int t)
{
if (all[m][n] == '+') {
mintime = min(mintime, totaltime);
flag = 1;
return;
}
if (visited[m][n] || m < 0 || n < 0 || m >= M || n >= N)
return;
else if (!visited[m][n] && all[m][n] == '#' && t > 0) {
if (totaltime+1 >= mintime)
return;
if (totaltime+1 >= minl[m][n][t])
return;
++totaltime;
minl[m][n][t] = totaltime;
visited[m][n] = 1;
dfs(m - 1, n, t - 1);
dfs(m + 1, n, t - 1);
dfs(m, n - 1, t - 1);
dfs(m, n + 1, t - 1);
--totaltime;
visited[m][n] = 0;
}
else if (!visited[m][n] && all[m][n] == '*' || all[m][n]=='@') {
if (totaltime+1 >= mintime)
return;
if (totaltime+1 >= minl[m][n][t])
return;
++totaltime;
minl[m][n][t] = totaltime;
visited[m][n] = 1;
dfs(m - 1, n, t);
dfs(m + 1, n, t);
dfs(m, n - 1, t);
dfs(m, n + 1, t);
--totaltime;
visited[m][n] = 0;
}
}
int main()
{
while (cin >> M >> N >> T)
{
int mi, ni; //记录起点位置
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
cin >> all[i][j];
if (all[i][j] == '@') {
mi = i; ni = j;
}
}
}
totaltime = 0;
mintime = 0x3f3f3f3f;
memset(visited, 0, sizeof(visited));
memset(minl, 0x3f3f3f3f, sizeof(minl));
dfs(mi, ni, T);
if (flag == 1)
cout << mintime;
else
cout << -1;
}
return 0;
}