有一个N*M的迷宫,’.’代表空位置,’b’代表有障碍物,机器人需要从左上角走到右下角,且只能向右或者向下行进,而且只有当向下或者向右遇到障碍物或超出边界时才能改变行进方向,机器人在初始位置向右行走。由于这些限制条件,很可能机器人无法走出迷宫,这时候可以考虑去掉一些位置上的障碍物,求去掉障碍物的最小数目。
思路分析
采用回溯的方法解决这一问题。机器人遇到障碍物的时候,有两种选择,一是搬走障碍物按原方向行走,二是转向。这两种选择可以拆分为以下几种情况:
- 机器人在最后一个位置,终止行进,统计共搬走的障碍物数目。
- 机器人处于最后一行,无论下一步是否有障碍物,都只能向右行进。
- 机器人处于最后一列,只能向下行进。
- 机器人向右行走,下一位置有障碍物,可选择搬走障碍物,或者向下行走(若向下行走也有障碍物,则搬走)。
- 机器人向下行走,下一位置有障碍物,可选择搬走障碍物,或者向右行走(若向右行走也有障碍物,则搬走)。
- 机器人下一位置无障碍物,保持原方向行走。
代码实现
使用一个变量ans记录当前找到的最小搬运数目,初始化为n+m-1(即假设每走一步都要搬走障碍物)
使用变量pre记录当前已搬运障碍物数据,若pre>ans,则当前不是最优解,终止遍历。
使用布尔型变量toRight记录当前行进方向,为true表示向右行走,false表示向下行走。
终止条件:位置越界,或者到达右下角,或者当前搬运数目大于候选最优解(pre>ans)。
void backTrace(vector<string> vec, int *ans, int x, int y, int pre, bool toRight){
if(x<0 || x>=vec.size() || y<0 || y>=vec[0].size() || pre>*ans) return;
if(x==vec.size()-1 && y==vec[0].size()-1){
*ans = min(*ans, pre);
}else if(x==vec.size()-1){
if(vec[x][y+1]=='b') backTrace(vec, ans, x, y+1, pre+1, true);
else backTrace(vec, ans, x, y+1, pre, true);
}else if(y==vec[0].size()-1){
if(vec[x+1][y]=='b') backTrace(vec, ans, x+1, y, pre+1, false);
else backTrace(vec, ans, x+1, y, pre, false);
}else{
if(vec[x][y+1]=='b' && vec[x+1][y]=='b'){
backTrace(vec, ans, x, y+1, pre+1, true);
backTrace(vec, ans, x+1, y, pre+1, false);
}else if(vec[x][y+1]=='b'){
backTrace(vec, ans, x+1, y, pre, false);
if(toRight) backTrace(vec, ans, x, y+1, pre+1, true);
}else if(vec[x+1][y]=='b'){
if(!toRight) backTrace(vec, ans, x+1, y, pre+1, false);
backTrace(vec, ans, x, y+1, pre, true);
}else{
if(toRight) backTrace(vec, ans, x, y+1, pre, true);
else backTrace(vec, ans, x+1, y, pre, false);
}
}
}
备注
本代码通过率为:WA 50%
本题目应该可以转换成动态规划的dp算法求解,由于本人能力有限,仅能提供一个思路:用两个维度记录当前位置横纵坐标,再用一个维度记录当前行进方向(0代表向右,1向下)。