主题:迷惑!我用堆栈法干迷宫问题出现不同结果?
这是数据结构书上的一道例题,很多人都不陌生吧.
#include<stdio.h>
#define M 8
#define N 8
#define MaxSize 500
int mg[M+2][N+2]=
{
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},
{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
int mgpath(int xi,int yi,int xe,int ye) /*求解路径为:(xi,yi)->(xe,ye)*/
{
struct
{
int i; /*当前方块的行号*/
int j; /*当前方块的列号*/
int di; /*di是下一可走相邻方位的方位号*/
}st[MaxSize]; /*定义栈*/
int top=-1; /*初始化栈地址*/
int i,j,k,di,find;
top++; /*初始方块即入口进栈*/
st[top].i=xi;st[top].j=yi;
st[top].di=-1;mg[1][1]=-1;
while(top>-1) /*栈不为空时循环*/
{
i=st[top].i;j=st[top].j;di=st[top].di; /*取栈顶方块*/
if(i==xe&&j==ye) /*找到了出口,输出路径*/
{
printf("The Route is:\n");
for(k=0;k<=top;k++)
{
printf("\t(%d,%d)",st[k].i,st[k].j);
if((k+1)%5==0) /*每输出5个方块后换一行*/
printf("\n");
}
printf("\n");
return (1); /*找到一条路径后返回1*/
}
find=0;
while(di<4&&find==0) /*找(i,j)方块的下一个可走方块*/
{
di++; /*找下一个方位*/
switch(di)
{
case 0: i=st[top].i-1;j=st[top].j;break;
case 1: i=st[top].i;j=st[top].j+1;break;
case 2: i=st[top].i+1;j=st[top].j;break;
case 3: i=st[top].i;j=st[top].j-1;break;
default:break;
}
if(mg[i][j]==0) /*找到下一个可走相邻方块*/
find=1;
}
if(find==1) /*找到了下一个可走相邻方块*/
{
st[top].di=di; /*修改原栈顶元素的di值*/
top++; /*将可走的相邻方块进栈*/
st[top].i=i;st[top].j=j;st[top].di=-1;
mg[i][j]=-1; /*避免重复走到该方块,将其置为1*/
}
else /*没有相邻方块可走,则退栈*/
{
mg[st[top].i][st[top].j]=0; /*让该位置变为其他路径可走方块=1也行啊?*/
top--; /*将该方块退栈*/
}
}
return (0); /*表示没有可走路径,返回0*/
}
int main()
{
mgpath(1,1,M,N);
getch();
}
书上只打印出了一条路线,现在要打印所有路径.把函数mgpath类型改为void,去掉return会打印出168种结果.我知道偶次的时候跟前面一次的路径相同,但是他们在出口行多了个向左拐的过程,在退栈,所以表面上看是一样的.
我想出了两种方法:
#include<stdio.h>
#define M 8
#define N 8
#define MaxSize 500
int mg[M+2][N+2]=
{
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},
{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
struct
{
int i;
int j;
int di;
}st[MaxSize];
int Ntd=1,top=-1;
void print()
{
int k;
printf("The %dth Route is:\n",Ntd);
for(k=0;k<=top;k++)
{
printf("(%d,%d)\t",st[k].i,st[k].j);
if((k+1)%5==0)
printf("\n");
}
printf("\n");
Ntd++;
}
void mgpath(int xi,int yi,int xe,int ye)
{
int i,j,k,find,di;
top=0;
st[top].i=xi,st[top].j=yi,st[top].di=-1;
mg[1][1]=-1;
while(top>-1)
{
i=st[top].i,j=st[top].j,di=st[top].di;
if(i==xe&&j==ye)
{
if(find==1)/*方法一:插入一句*/
print();
}
find=0;
while(di<4&&find==0)
{
di++;
switch(di)
{
case 1:i=st[top].i-1,j=st[top].j;break;
case 2:i=st[top].i,j=st[top].j+1;break;
case 3:i=st[top].i+1,j=st[top].j;break;
case 4:i=st[top].i,j=st[top].j-1;break;
default:break;
}
if(mg[i][j]==0)
find=1;
}
if(find==1)
{
st[top].di=di;
top++;
st[top].i=i;st[top].j=j;st[top].di=-1;
mg[i][j]=-1;
}
else
{
/*if(st[top-1].i==xe&&st[top-1].j==ye)
{方法2:插入这块代码
mg[st[top].i][st[top].j]=1;
top--;
mg[st[top].i][st[top].j]=0;
top--;
}*/
mg[st[top].i][st[top].j]=0; top--;
}
}
}
int main()
{
mgpath(1,1,M,N);
getch();
return 0;
}
方法1:在输出前判断,只有前进到出口才算,撤退到出口会与前面的路径重复就不打印出了*/
方法2:如果撤退到出口,则连出口一起弹出,封锁这个位置(这里是mg[8,7])省了后面来回.
最后的结果居然不同?一个是84,一个是80.方法1更有生存力,不过我很难找到方法2的错误!我表达的不太清楚,看到这帖的希望有兴趣帮下忙.
#include<stdio.h>
#define M 8
#define N 8
#define MaxSize 500
int mg[M+2][N+2]=
{
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},
{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
int mgpath(int xi,int yi,int xe,int ye) /*求解路径为:(xi,yi)->(xe,ye)*/
{
struct
{
int i; /*当前方块的行号*/
int j; /*当前方块的列号*/
int di; /*di是下一可走相邻方位的方位号*/
}st[MaxSize]; /*定义栈*/
int top=-1; /*初始化栈地址*/
int i,j,k,di,find;
top++; /*初始方块即入口进栈*/
st[top].i=xi;st[top].j=yi;
st[top].di=-1;mg[1][1]=-1;
while(top>-1) /*栈不为空时循环*/
{
i=st[top].i;j=st[top].j;di=st[top].di; /*取栈顶方块*/
if(i==xe&&j==ye) /*找到了出口,输出路径*/
{
printf("The Route is:\n");
for(k=0;k<=top;k++)
{
printf("\t(%d,%d)",st[k].i,st[k].j);
if((k+1)%5==0) /*每输出5个方块后换一行*/
printf("\n");
}
printf("\n");
return (1); /*找到一条路径后返回1*/
}
find=0;
while(di<4&&find==0) /*找(i,j)方块的下一个可走方块*/
{
di++; /*找下一个方位*/
switch(di)
{
case 0: i=st[top].i-1;j=st[top].j;break;
case 1: i=st[top].i;j=st[top].j+1;break;
case 2: i=st[top].i+1;j=st[top].j;break;
case 3: i=st[top].i;j=st[top].j-1;break;
default:break;
}
if(mg[i][j]==0) /*找到下一个可走相邻方块*/
find=1;
}
if(find==1) /*找到了下一个可走相邻方块*/
{
st[top].di=di; /*修改原栈顶元素的di值*/
top++; /*将可走的相邻方块进栈*/
st[top].i=i;st[top].j=j;st[top].di=-1;
mg[i][j]=-1; /*避免重复走到该方块,将其置为1*/
}
else /*没有相邻方块可走,则退栈*/
{
mg[st[top].i][st[top].j]=0; /*让该位置变为其他路径可走方块=1也行啊?*/
top--; /*将该方块退栈*/
}
}
return (0); /*表示没有可走路径,返回0*/
}
int main()
{
mgpath(1,1,M,N);
getch();
}
书上只打印出了一条路线,现在要打印所有路径.把函数mgpath类型改为void,去掉return会打印出168种结果.我知道偶次的时候跟前面一次的路径相同,但是他们在出口行多了个向左拐的过程,在退栈,所以表面上看是一样的.
我想出了两种方法:
#include<stdio.h>
#define M 8
#define N 8
#define MaxSize 500
int mg[M+2][N+2]=
{
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},
{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
struct
{
int i;
int j;
int di;
}st[MaxSize];
int Ntd=1,top=-1;
void print()
{
int k;
printf("The %dth Route is:\n",Ntd);
for(k=0;k<=top;k++)
{
printf("(%d,%d)\t",st[k].i,st[k].j);
if((k+1)%5==0)
printf("\n");
}
printf("\n");
Ntd++;
}
void mgpath(int xi,int yi,int xe,int ye)
{
int i,j,k,find,di;
top=0;
st[top].i=xi,st[top].j=yi,st[top].di=-1;
mg[1][1]=-1;
while(top>-1)
{
i=st[top].i,j=st[top].j,di=st[top].di;
if(i==xe&&j==ye)
{
if(find==1)/*方法一:插入一句*/
print();
}
find=0;
while(di<4&&find==0)
{
di++;
switch(di)
{
case 1:i=st[top].i-1,j=st[top].j;break;
case 2:i=st[top].i,j=st[top].j+1;break;
case 3:i=st[top].i+1,j=st[top].j;break;
case 4:i=st[top].i,j=st[top].j-1;break;
default:break;
}
if(mg[i][j]==0)
find=1;
}
if(find==1)
{
st[top].di=di;
top++;
st[top].i=i;st[top].j=j;st[top].di=-1;
mg[i][j]=-1;
}
else
{
/*if(st[top-1].i==xe&&st[top-1].j==ye)
{方法2:插入这块代码
mg[st[top].i][st[top].j]=1;
top--;
mg[st[top].i][st[top].j]=0;
top--;
}*/
mg[st[top].i][st[top].j]=0; top--;
}
}
}
int main()
{
mgpath(1,1,M,N);
getch();
return 0;
}
方法1:在输出前判断,只有前进到出口才算,撤退到出口会与前面的路径重复就不打印出了*/
方法2:如果撤退到出口,则连出口一起弹出,封锁这个位置(这里是mg[8,7])省了后面来回.
最后的结果居然不同?一个是84,一个是80.方法1更有生存力,不过我很难找到方法2的错误!我表达的不太清楚,看到这帖的希望有兴趣帮下忙.