今天看到了一个很有意思的题目:
小青蛙有一天不小心落入了一个地下迷宫,小青蛙希望用自己仅剩的体力值P跳出这个地下迷宫。为了让问题简单,假设这是一个n*m的格子迷宫,迷宫每个位置为0或者1,0代表这个位置有障碍物,小青蛙达到不了这个位置;1代表小青蛙可以达到的位置。小青蛙初始在(0,0)位置,地下迷宫的出口在(0,m-1)(保证这两个位置都是1,并且保证一定有起点到终点可达的路径),小青蛙在迷宫中水平移动一个单位距离需要消耗1点体力值,向上爬一个单位距离需要消耗3个单位的体力值,向下移动不消耗体力值,当小青蛙的体力值等于0的时候还没有到达出口,小青蛙将无法逃离迷宫。现在需要你帮助小青蛙计算出能否用仅剩的体力值跳出迷宫(即达到(0,m-1)位置)。
输入描述:
输入包括n+1行:
第一行为三个整数n,m(3 <= m<= 10,3 <= n <= 10),P(1 <= P <= 100)
接下来的n行:
每行m个0或者1,以空格分隔
输出描述:
如果能逃离迷宫,则输出一行体力消耗最小的路径,输出格式见样例所示;如果不能逃离迷宫,则输出"Can not escape!"。 测试数据保证答案唯一
示例1
输入
4 4 10 1 0 0 1 1 1 0 1 0 1 1 1 0 0 1 1
输出
[0,0],[1,0],[1,1],[2,1],[2,2],[2,3],[1,3],[0,3]
单看文字可能不太直观,我们以示例1画图来说明一下:
根据规则,只有两种路线绿色的路线一共花费了12点体力,所以无法走出迷宫,紫色路线一共花费了9点体力所以我们应将紫色路线所走的每一步打印出来,就是示例的最终结果;
若要使用代码解决这个问题,我们需要进行几步思考:
构建迷宫规则
- 题目说的很清楚,小青蛙在迷宫中水平移动一个单位距离需要消耗1点体力值,向上爬一个单位距离需要消耗3个单位的体力值,向下移动不消耗体力值,迷宫不大于10*10,青蛙体力必须大于0才可以行动,所以我们可以将这些迷宫的格子看成一个个二维平面上的点,并得出青蛙的移动无非就是对它本来的点进行横/纵坐标的加减,将整个迷宫的点装进一个二维数组里:
int action[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};//上下左右的动作;
int maze[10][10];//存放迷宫每个格子是不是石头;
int cost[4] = {3,0,1,1};//每个动作对用所消耗的体力
int final_p = -1;//到达出口时青蛙的体力
- 迷宫的每个格子既然已经被我们看成了一个二维坐标点,那麽它也就具有了横纵坐标,我们使用一个结构体来集体描述这些信息:
struct Mazepoint{
Mazepoint(int x,int y)//纵,横坐标,maze[x][y]里x表示的是一维数组个数,也就是纵坐标;
:_x(x)
,_y(y)
{}
int _x;
int _y;
};
查找最佳路线
- 因为成功到达出口的路径不止一条,所以我们需要创建两个vector,一个用来存放当前的路径,一个用来存放最短的路径,至于如何得到可行的路径,在题目给定只有最多十层的情况下,我采用递归思想,即当我从起点开始,我将分别试探上下左右四个方向,那个是可行的,然后再以此为基础继续像四个方向扩散,一次覆盖整个迷宫的可能性,但需要注意:每次到达一个点后,为了不会被以后再走到(相当于回头路),我们将这个点的值置为Root,当这条路径结束后,将在该点的值再置回1(可通行)并将当前路径中的这个点弹出(因为是全局的,不弹出会污染别的路径);每一次得到新的点的时候,一定要进行合法性判断,否则就会越界访问;
- 在一条路径成功的到达出口时,我们将此时所胜的体力值与之前最小路径所剩的体力值进行比较,更新最小路径和最大剩余体力数;最后打印最短路径;
vector<Mazepoint> path;
vector<Mazepoint> best;
void Search(int x,int y,int p1){
Mazepoint ne (x,y);
path.push_back(ne);
if(x==0&&y==m-1&&p1>=0){
if(p1>final_p)
final_p = p1;
best = path;
path.pop_back();
return;
}
maze[x][y]= Root;
if(p>0){
for(int i =0;i<4;i++){
int new_x = x+action[i][0];
int new_y = y+action[i][1];
int new_p = p1-cost[i];
if(new_x<n && new_x>=0 && new_y<m && new_y>=0 && new_p>=0 && maze[new_x][new_y]==1)
Search(new_x,new_y,new_p);
}
}
path.pop_back();//因为是全局的所以用完就要扔掉;
maze[x][y] = 1;
}
输出最佳路径
- 到这里已经是最后一步了,我们只需要按照要求,调用best打印其中的每个点即可:
void PrintPath(){
int size = best.size();
for(int i = 0;i<size;i++){
cout<<"["<<best[i]._x<<","<<best[i]._y<<"]";
if(i!=size-1)
cout<<",";
else
cout<<endl;
}
}
主函数
- 这里主要是实现初始化迷宫(确定每个点哪里能走哪里是石头),然后根据search结果进行不同的处理:
int main(){
cin>>n>>m>>p;
for(int i = 0;i<n;i++){
for(int j = 0;j<m;j++){
cin>>maze[i][j];
}
}
Search(0,0,p);
if(final_p==-1)
cout<<"Can not escape!"<<endl;
else
PrintPath();
return 0;
}
完整的代码可以到我的GItHub上查看,欢迎交流学习!
yo~
yo~
如果觉得不错~
请别忘了点个赞~
Bro你的鼓励~
给我坚持的勇气~
Peace out~