此程序有小bug,修改在最后
转自:https://blog.csdn.net/qq_37414405/article/details/85935033
思路:利用栈穷举路径,从而来得到问题的解答
注意:当前路径可通,指未曾走到过的通道块(即不能是已经压入栈中的通道块又被重复压入,这样的话就不是简单路径了)。并且该通道块不能是曾经纳入过路径的通道块(即不能之前弹出了又压入进去,这样的话就会在死胡同里转圈)
代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
原程序:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
typedef int Status;
typedef struct
{
int row;
int col;
}PosType;
typedef struct
{
int ord; //通道块在路径上的“序号”
PosType seat; //通道块在迷宫中的“坐标位置”
int di; //从此通道块走向下一通道块的“方向”
}SElemType;
typedef struct
{
SElemType *base; //在栈构造之前和销毁之后,base的值为NULL
SElemType *top; //栈顶指针
int stacksize; //当前已分配的存储空间,以元素为单位
}SqStack;
int MazeMap[10][10] = //迷宫地图为全局变量
{
//0,1,2,3,4,5,6,7,8,9
{0,0,0,0,0,0,0,0,0,0}, //0
{0,1,1,0,1,1,1,0,1,0}, //1
{0,1,1,0,1,1,1,0,1,0}, //2
{0,1,1,1,1,0,0,1,1,0}, //3
{0,1,0,0,0,1,1,1,1,0}, //4
{0,1,1,1,0,1,1,1,1,0}, //5
{0,1,0,1,1,1,0,1,1,0}, //6
{0,1,0,0,0,1,0,0,1,0}, //7
{0,0,1,1,1,1,1,1,1,0}, //8
{0,0,0,0,0,0,0,0,0,0} //9
};
//***************注意在数组中与坐标的不同表示方法,容易混淆
/*******************************声明部分****************************************/
/*******************************函数部分****************************************/
Status InitStack(SqStack *S)
{
(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if(!(*S).base)
exit(OVERFLOW);
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
Status Push(SqStack *S,SElemType e)
{
*(*S).top++ = e;
return OK;
}
Status Pop(SqStack *S,SElemType *e)
{
if((*S).top == (*S).base)
return ERROR;
*e = *(--(*S).top);
return OK;
}
Status StackEmpty(SqStack S)
{
if(S.top==S.base)
return OK;
return ERROR;
}
void PrintMaze( )
{
printf("\n 迷宫的地图为:\n\n");
int i,j;
for(i = 0;i<10;i++){
for(j = 0;j<10;j++)
printf(" %3d",MazeMap[i][j]);
printf("\n");
}
}
Status FootPrint(PosType pos,int curstep)
{
MazeMap[pos.row][pos.col] = curstep;
return OK;
}
Status Pass(PosType pos)
{
if(MazeMap[pos.row][pos.col] == 1)
return TRUE;
return FALSE;
}
PosType NextPos(PosType CurPos,int i)
{
switch(i)
{
case 1:
++CurPos.row; //东
break;
case 2:
++CurPos.col; //南
break;
case 3:
--CurPos.row; //西
break;
case 4:
--CurPos.col; //北
break;
}//switch
return CurPos;
}
void MakePrint(PosType pos)
{
printf("(%d,%d)走不通\n",pos.row,pos.col);
MazeMap[pos.row][pos.col] = 0; //将走不通的块替换为墙壁
}
Status MazePath(PosType start,PosType end)
{
SqStack S;
PosType curpos;
SElemType e;
int curstep;
InitStack(&S);
curpos = start; //设定“当前位置”为“入口位置”
curstep = 1; //探索第一步
printf("\n起点:(%d,%d)",start.row,start.col);
do{
if(Pass(curpos)){ //当前位置可以通过,即使未曾走到过的通道块
FootPrint(curpos,curstep); //留下足迹
printf(" ->(%3d,%3d)\n",curpos.row,curpos.col);
e.ord = curstep;
e.seat = curpos;
e.di = 1;
Push(&S,e); //加入路径
if(curpos.row == end.row && curpos.col == end.col){ //到达终点
printf("到达终点:(%3d,%3d)\n",e.seat.col,e.seat.row);
return TRUE;
}
curpos = NextPos(curpos,1); //下一位置是当前位置的东邻
curstep++; //探索下一步
printf("step:%d",curstep);
}//if
else{ //当前位置不能通过
if(!StackEmpty(S)){
Pop(&S,&e);
while(e.di == 4 && !StackEmpty(S)){
MakePrint(e.seat);
Pop(&S,&e);
curstep--;
printf("倒退到(%3d,%3d)\n",e.seat.col,e.seat.row);
}//while
if(e.di < 4){
++e.di; //换下一个方向探索
Push(&S,e);
curpos = NextPos(e.seat,e.di); //设定当前位置是该新方向上的相邻块
}//if
}//if
}//else
}while(!StackEmpty(S));
printf("对不起,找不到出口\n");
return FALSE;
}
/*******************************主函数部分**************************************/
int main()
{
PrintMaze();
PosType Start,End;
Start.col = 1;
Start.row = 1;
End.col = 8;
End.row = 8;
MazePath(Start,End);
PrintMaze();
return 0;
}
bug:
如果把MazeMap改为:
//0,1,2,3,4,5,6,7,8,9
{0,0,0,0,0,0,0,0,0,0}, //0
{0,1,1,1,1,1,1,0,1,0}, //1
{0,1,0,1,1,1,1,0,1,0}, //2
{0,0,1,1,1,0,0,1,1,0}, //3
{0,1,0,1,0,1,1,1,1,0}, //4
{0,1,1,1,0,1,1,1,1,0}, //5
{0,1,0,1,1,1,0,1,1,0}, //6
{0,1,0,0,0,1,0,0,1,0}, //7
{0,0,1,1,1,1,1,1,1,0}, //8
{0,0,0,0,0,0,0,0,0,0} //9
则输出为:
0 0 0 0 0 0 0 0 0 0
0 3 4 5 1 1 1 0 1 0
0 2 0 6 1 1 1 0 1 0
0 0 1 7 1 0 0 1 1 0
0 1 0 8 0 1 1 1 1 0
0 1 1 9 0 1 1 1 1 0
0 1 0 10 11 12 0 1 1 0
0 1 0 0 0 13 0 0 1 0
0 0 1 1 1 14 15 16 17 0
0 0 0 0 0 0 0 0 0 0
显然不太正确,主要的问题在于,首选NextPos(,1)即当前位置能通过时,先向下探索,从(1,1)到(2,1),Pass(2,1)=1,留下足迹MazeMap[2][1]=curstep=2(注意,此时Pass(2,1)不再为1),显然(2,1)没法往后走。当di增加到3时,NextPos又回到(1,1),而MazeMap[1][1]=1(因为在(1,1)点时,curstep恰好是1)导致Pass为真,所以FootPrint(1,1,curstep=3)使MazeMap[1][1]=3,接下来由于之前FoorPrint改变了MazeMap[2][1]使之不再为1,Pass返回0,所以就不能再从(1,1)->(2,1),而是1,1)->(1,2)这就出现了上边的bug(说的我自己都糊涂了,还是一步一步推一下比较清楚)
解决的办法是不能让某一点FootPrint之后在MazeMap中的值还是1,否者就会导致无法判断是否曾经到达过这一点(因为能到达的点在MazeMap中本来就是1)。仔细分析可知,只有在起点(1,1)处才会有这个问题,因为只有这一点curstep才会是1,所以让(1,1)点FootPrint之后的值为0,如果能够找到出口,在打印路径时再把值改为1.
更改后程序如下:
//
// Created by dgm on 19-3-2.
//
#define MaxSize 1000
#define Increment 100
#include <iostream>
#include <iomanip>
using namespace std;
typedef int Status;
typedef struct {
int row;
int col;
}PosType;
typedef struct {
int ord;
PosType seat;
int di;
}ElemType;
typedef struct Stack{
ElemType*top;
ElemType*base;
unsigned int stack_size;
}Stack;
int MazeMap[10][10] =
{
{0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,0,1,0},
{0,1,0,1,1,1,1,0,1,0},
{0,0,1,1,1,0,0,1,1,0},
{0,1,0,1,0,1,1,1,1,0},
{0,1,1,1,0,1,1,1,1,0},
{0,1,0,1,1,1,0,1,1,0},
{0,1,0,0,0,1,0,0,1,0},
{0,0,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0}
};
void PrintMaze()
{
cout<<"the map of maze"<<endl;
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
cout<<setw(3)<<MazeMap[i][j]<<" ";
cout<<endl;
}
}
void InitStack(Stack&S)
{
S.base=(ElemType*)malloc(MaxSize* sizeof(ElemType));
if(!S.base)exit(EOVERFLOW);
S.top=S.base;
S.stack_size=MaxSize;
}
void Push(Stack&S,ElemType e)
{
if(S.top-S.base>=S.stack_size)
S.base=(ElemType*)malloc((MaxSize+Increment)* sizeof(ElemType));
if(!S.base)exit(EOVERFLOW);
*S.top=e;
S.top++;
}
void Pop(Stack&S,ElemType&e)
{
if(S.top==S.base)return;
e=*(--S.top);
}
bool StackEmpty(Stack&S)
{
return S.base==S.top;
}
void FootPrint(PosType pos,int curstep)
{
if(pos.row==1&&pos.col==1) //**********************************************
{
MazeMap[pos.row][pos.col]=0; //*******************改动***********************
return;
} //**********************************************
MazeMap[pos.row][pos.col]=curstep;
}
Status Pass(PosType pos)
{
if(MazeMap[pos.row][pos.col]==1)return 1;
return 0;
}
PosType NextPos(PosType CurPos,int i)
{
switch (i)
{
case 1:
++CurPos.row;
break;
case 2:
++CurPos.col;
break;
case 3:
--CurPos.row;
break;
case 4:
--CurPos.col;
break;
}
return CurPos;
}
void MakePrint(PosType pos)
{
cout<<"("<<pos.row<<","<<pos.col<<") was blocked"<<endl;
MazeMap[pos.row][pos.col]=0;
}
Status MazePath(PosType start,PosType end)
{
Stack S;
PosType curpos;
ElemType e;
int curstep;
InitStack(S);
curpos=start;
curstep=1;
cout<<"begin with: "<<"("<<start.row<<","<<start.col<<")"<<endl;
do{
if(Pass(curpos)){
FootPrint(curpos,curstep);
cout<<" ->"<<"("<<curpos.row<<","<<curpos.col<<")"<<endl;
e.ord=curstep;
e.seat=curpos;
e.di=1;
Push(S,e);
if(curpos.row==end.row&&curpos.col==end.col)
{
cout<<"(finished)"<<endl;
return 1;
}
curpos=NextPos(curpos,1);
curstep++;
cout<<" step:"<<curstep;
}
else
{
if(!StackEmpty(S))
{
Pop(S,e);
while(e.di==4&&!StackEmpty(S))
{
MakePrint(e.seat);
Pop(S,e);
curstep--;
cout<<" back to ""("<<e.seat.row<<","<<e.seat.col<<")";
}
if(e.di<4)
{
++e.di;
Push(S,e);
curpos=NextPos(e.seat,e.di);
}
}
}
}while(!StackEmpty(S));
cout<<"no exit"<<endl;
return 0;
}
int main()
{
PrintMaze();
PosType Start,End;
Start.row=1,Start.col=1;
End.row=8,End.col=8;
if(MazePath(Start,End))
{
MazeMap[1][1]=1; //*********************改动*********************
PrintMaze();
}
return 0;
}