题目
1、问题描述:
以一个m×n的长方阵表示迷宫,0和1分别表示迷宫中的道路和障碍.设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论.
2、基本要求:
首先实现一个以链表做存储结构的栈类型,然后编写一个求解迷宫的非递归程序.求得的通路以三元组(i,j,d)的形式输出,其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向.如:对于下列数据的迷宫,输出的一条通路为(1,1,1),(1,1,2),(2,2,2),(3,2,3),(3,1,2),….
3、测试数据:
迷宫测试数据如下:左上角(1,1)为入口,右下角(8,9)为出口
1 2 3 4 5 6 7 8
0
0 1 0 0 0 1 0
0 0 1 0 0 0 1 0
0 0 0 0 1 1 0 1
0 1 1 1 0 0 1 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 1
0 1 1 1 1 0 0 1
1 1 0 0 0 1 0 1
1 1 0 0
0 0 0 0
4、实现提示:
计算机解迷宫通常用的是“穷举求解”方法,即从入口出发,顺着某一个方向进行探索,若能走通,则继续往前进;否则沿着原路退回,换一个方向继续探索,直至出口位置,求得一条通路。假如所有可能的通路都探索到而未能到达出口,则所设定的迷宫没有通路。
可以二维数组存储迷宫数据,通常设定入口的下标为(1,1),出口点的下标为(n,n)。为处理方便起见,可在迷宫的四周加一圈障碍。对于迷宫中任一位置,均可约定有东、南、西、北四个方向可通。
5、选做内容 :
(1)编写递归形式的算法,求得迷宫中所有可能的通路;
(2)以方阵形式输出迷宫及其通路。
链表结点
#include
using namespace std;
template<typename Type>class LinkStack;
template<typename Type>class StackNode{
private:
friend class LinkStack;
StackNode(Type dt,StackNode *next=NULL):m_data(dt),m_pnext(next){}
private:
Type m_data;
StackNode *m_pnext;
};
链表存储的栈结构实现
#include
#include "StackNode.h"
template<typename Type> class LinkStack{
public:
LinkStack():m_ptop(NULL){}//构造
~LinkStack(){MakeEmpty();} //析构
public:
void MakeEmpty();//make the stack empty
void Push(const Type item); //push the data
Type Pop();//pop the data
Type GetTop() const;//get the data
void Print();//print the stack
bool IsEmpty()const{
return m_ptop==NULL;
}
private:
StackNode *m_ptop;
};
template<typename Type> void LinkStack::MakeEmpty(){
StackNode *pmove;
while(m_ptop!=NULL){
pmove=m_ptop;
m_ptop=m_ptop->m_pnext;
delete pmove;
}
}
template<typename Type>void LinkStack::Push(const Type item){
m_ptop=new StackNode(item,m_ptop);
}
template<typename Type>Type LinkStack::GetTop()const{
if(IsEmpty()){
cout<<"There is no elements\n";
exit(1);
}
return m_ptop->m_data;
}
template<typename Type>Type LinkStack::Pop(){
if(IsEmpty()){
cout<<"there is no element\n";
exit(1);
}
StackNode*pdel=m_ptop;
m_ptop=m_ptop->m_pnext;
Type temp=pdel->m_data;
delete pdel;
return temp;
}
template<typename Type>void LinkStack::Print(){
StackNode*pmove=m_ptop;
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 迷宫通路输出 *\n");
printf("\t\t*\t\t start \t\t\t*\n");
while(pmove!=NULL){
printf("\t\t*\t\t ↓ \t\t\t*\n");
printf("\t\t*\t (%d,%d",pmove->m_data.x,pmove->m_data.y);
switch(pmove->m_data.z){
case 1:{
printf(",东) *\n");
break;
}
case 2:{
printf(",南) *\n");
break;
}
case 3:{
printf(",西) *\n");
break;
}
case 4:{
printf(",北) *\n");
break;
}
default:{
printf(") *\n");
break;
}
}
pmove=pmove->m_pnext;
}
printf("\t\t*\t\t end \t\t\t*\n");
printf("\t\t*****************************************\n");
}
求解的代码(包括选做)
#include
#include
#include"LinkStack.h"
#include
using namespace std;
const int maxn=60;
int xto[5]={0,1,0,-1,0};//东,南,西,北
int yto[5]={0,0,1,0,-1};
int tu[65][65];
bool vis[65][65];
char maze[65][65];
int sx,sy,ex,ey,n=1,m=1,t,q,fff=1;
//x,y,方向
struct messege{
int x,y,z;
//messege(int &_x,int &_y):x(_x),y(_y){}
};
LinkStackpath;
//判断字符或者数值
int panshu(){
string c;
int ten=1,sum=0,i=0,flag=1;
cin>>c;
int l=c.size();
if(c[0]=='-'){
flag=-1;
i++;
}
while(iif(c[i]>='0'&&c[i]<='9'){
sum=ten*sum+(c[i]-'0');
ten*=10;
}
else return -2;
i++;
}
sum*=flag;
//printf("sum=%d\n",sum);
return sum;
}
//非递归找一条路并输出
bool dfs(){
path.MakeEmpty();
struct messege nex,now;//走到这个点了
now.x=sx;
now.y=sy;
now.z=0;
path.Push(now);
//cout<<"hell0\n";
while(!path.IsEmpty()){
now=path.GetTop();
int i;
for(i=1;i<=4;i++){
nex.x=now.x+xto[i];
nex.y=now.y+yto[i];//下一个点
//下一个可以走
if(nex.x>0&&nex.x<=n&&nex.y>0&&nex.y<=m&&!vis[nex.x][nex.y]){
path.Pop();
now.z=i;
path.Push(now);//确定now这个点
//printf("get(%d,%d,%d)\n",now.x,now.y,now.z);
vis[now.x][now.y]=1;
nex.z=0;
path.Push(nex);
if(nex.x==ex&&nex.y==ey)return true;
break;
}
}
//下一个不可以走,且绕了一周,证明now这个点不行的
if(i>4){
vis[now.x][now.y]=1;
path.Pop();
//printf("return \n");
}
}
return 0;
}
//输出路径
void pri(){
printf("\n\n\t\t**************************************************************\n");
printf("\t\t* #:障碍 .:通路 *\n");
printf("\t\t**************************************************************\n");
for(int i=1;i<=60;i++){// 行m
printf("\t\t*");
for(int j=1;j<=60&&i<=m+2;j++){//列 n
if(j<=n&&i<=m){
printf("%c",maze[j][i]);
}
else if(j>n+3&&j<=60)printf("#");
else printf(" ");
}
if(i<=m+2)printf("*\n");
else if(i>m+2&&i<=60)printf("############################################################*\n");
//else printf(" *\n");
}
printf("\t\t**************************************************************\n");
}
//菜单选择进入或退出
int menu(){
printf("\t\t*****************************************\n");
printf("\t\t* 迷宫求解程序 *\n");
printf("\t\t* 菜单 *\n");
printf("\t\t* 1.进入程序 0.退出程序 *\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****************************************\n");
printf("\t\t请输入你的选择:");
t=panshu();
getchar();
if(t==1)return 1;
else if(t==-1||t==0)return -1;
else return 0;
}
//再见结束
void bye(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 迷宫求解程序 *\n");
printf("\t\t* 欢迎下次来玩 *\n");
printf("\t\t*****************************************\n");
}
//递归输出路径
void huisu(messege &now,int &flag){
if(now.x==ex&&now.y==ey){
flag=0;
printf("\n\n\n");
pri();
return;
}
messege nex;
for(int i=1;i<=4;i++){
nex.x=now.x+xto[i];
nex.y=now.y+yto[i];//下一个点
now.z=i;
//printf("(%d,%d,%d)\n",now.x,now.y,now.z);
if(nex.x>0&&nex.x<=n&&nex.y>0&&nex.y<=m&&!vis[nex.x][nex.y]&&maze[nex.x][nex.y]==' '){
vis[nex.x][nex.y]=1;
maze[nex.x][nex.y]='.';
huisu(nex,flag);
vis[nex.x][nex.y]=0;
maze[nex.x][nex.y]=' ';
}
}
return;
}
//进度条
void guodu(){
printf("\n\n\t\t正在加载:") ;
int i=16;
while(i--)
{ printf("|");
Sleep(30);
printf("\b");
printf("-");
Sleep(30);
printf("\b");
printf("/");
Sleep(30);
printf("\b");
printf(".");
Sleep(30);
}
printf("\n");
}
//初始化
void init_vis(){
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++){//列 tu(第几列,第几排)
for(int j=1;j<=n;j++){//行填充
if(tu[j][i]==1){
vis[j][i]=1;
maze[j][i]='#';
}
else maze[j][i]=' ';
}
}
if(maze[sx][sy]==' ')maze[sx][sy]='.';
}
//选择输出方式
void choosepri(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 选择输出(回车结束) *\n");
printf("\t\t* 1.指示输出一条路径 *\n");
printf("\t\t* 2.方阵输出所有路径 *\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****************************************\n");
printf("\t\t请输入你的选择:");
}
//输入大小
int inputsize(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 输入迷宫的大小(0);
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****PS.按下回车分隔两个数值*************\n");
printf("\t\t*****************************************\n");
printf("\t\t请输入|n:");
n=panshu();
printf("\t\t请输入|m:");
m=panshu();
if(n==-1||m==-1)return -1;
else if(060 &&060)return 1;
else return 0;
}
//输入迷宫
int inputmaze(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 输入迷宫(回车换下一排) *\n");
printf("\t\t* 1----障碍 0----空路 *\n");
printf("\t\t******PS.一旦输入有误请全部重新输入******\n");
printf("\t\t******PS.输入-1可以快速退出整个程序******\n");
printf("\t\t******PS.输入非0/1字符即可重新输入迷宫***\n");
printf("\t\t******PS.回车分隔每一排,空格分隔每一列**\n");
printf("\t\t*****************************************\n");
int i,j;
memset(vis,0,sizeof(vis));
for(i=1;i<=m;i++){//列 tu(第几列,第几排)
printf("\t\t");
for(j=1;j<=n;j++){//行填充
tu[j][i]=panshu();
if(tu[j][i]==1){
vis[j][i]=1;
maze[j][i]='#';
}
else if(tu[j][i]==0){
maze[j][i]=' ';
vis[j][i]=0;
}
else if(tu[j][i]==-1){
fff=0;
return -1;
}
else return 0;
}
}
return 1;
}
//输入起点(判错)
int instart(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 输入起点(x列,y排) *\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****PS.按下回车分隔两个数值*************\n");
printf("\t\t*****************************************\n");
printf("\t\t请输入|x:");
sx=panshu();
printf("\t\t请输入|y:");
sy=panshu();
if(maze[sx][sy]==' ')maze[sx][sy]='.';
if(sx==-1||sy==-1)return -1;
else if(00return 1;
else return 0;
}
//输入终点(判错)
int inend(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* 输入终点(x列,y排) *\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****PS.按下回车分隔两个数值*************\n");
printf("\t\t*****************************************\n");
printf("\t\t请输入|x:");
ex=panshu();
printf("\t\t请输入|y:");
ey=panshu();
if(ex==-1||ey==-1)return -1;
else if(00return 1;
else return 0;
}
//迷宫无解输出
void priworry(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* sorry~此迷宫无解 *\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****************************************\n");
}
//输入错误时要求重新输入 ,同时输出该选项重输入
void inputworry(){
printf("\n\n\t\t*****************************************\n");
printf("\t\t* sorry~输入错误 *\n");
printf("\t\t**************请重新输入*****************\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序*******\n");
printf("\t\t*****************************************\n");
}
//选择输出方式
int choose(){
choosepri();
q=panshu();
if(q==-1)return -1;
switch(q){
case 1:{
init_vis();
if(dfs()&&maze[sx][sy]=='.'){
LinkStackans;
while(!path.IsEmpty()){
ans.Push(path.GetTop());
path.Pop();
}
ans.Print();
}
else priworry();
break;
}
case 2:{
init_vis();
messege a;
a.x=sx;
a.y=sy;
if(maze[sx][sy]=='.'){
int flag=1;
printf("\n\n\t\t**************************************************************\n");
printf("\t\t* 你输入的数值迷宫 *\n");
printf("\t\t**************************************************************\n");
for(int i=1;i<=60;i++){
printf("\t\t*");
for(int j=1;j<=60;j++){
if(i<=m&&j<=n)printf("%d",tu[j][i]);//lie hang
else printf(" ");
}
printf("*\n");
}
printf("\t\t**************************************************************\n");
huisu(a,flag);
if(flag)priworry();
}
else priworry();
break;
}
default:{
getchar();
return 0;
break;
}
}
getchar();
return 1;
}
//是否想要消除上一个?
int del(){
printf("\t\t*****************************************\n");
printf("\t\t* 是否想要消除上一个? *\n");
printf("\t\t* 1.是 0.否 *\n");
printf("\t\t*****PS.输入-1可以快速退出整个程序********\n");
printf("\t\t*****************************************\n");
printf("\t\t请输入你的选择:");
t=panshu();
getchar();
if(t==1)return 1;
else if(t==-1)return -1;
else if(t==0)return 0;
else return -2;
}
int main(){
system("color 4f");
freopen("1.txt","r",stdin);
while(fff)
{
//输入选项
while(fff){
int z=menu();
if(z==-1)fff=0;
else if(z==1){
int p;
while(fff){
p=del();
if(p==-1)fff=0;//退出
else if(p==0)break;//否
else if(p==1)break;//是
else inputworry();//不符要求
}
if(p==0)break;//成功的
}
else inputworry();
}
//进度条
guodu();
system("cls");
//输入大小
while(fff){
int z=inputsize();
if(z==-1)fff=0;
else if(z==1){
int p;
while(fff){
p=del();
if(p==-1)fff=0;//退出
else if(p==0)break;//否
else if(p==1)break;//是
else inputworry();//不符要求
}
if(p==0)break;//成功的
}
else inputworry();
}
//输入迷宫 inputmaze
while(fff){
int z=inputmaze();
if(z==-1)fff=0;//退出
else if(z==1){//符合要求
int p;
while(fff){
p=del();
if(p==-1)fff=0;//退出
else if(p==0)break;//否
else if(p==1)break;//是
else inputworry();//不符要求
}
if(p==0)break;//成功的
}
else inputworry();//不符合要求
}
//起点instart
while(fff){
int z=instart();
if(z==-1)fff=0;
else if(z==1){
int p;
while(fff){
p=del();
if(p==-1)fff=0;//退出
else if(p==0)break;//否
else if(p==1)break;//是
else inputworry();//不符要求
}
if(p==0)break;//成功的
}
else inputworry();
}
//终点inend
while(fff){
int z=inend();
if(z==-1)fff=0;
else if(z==1){
int p;
while(fff){
p=del();
if(p==-1)fff=0;//退出
else if(p==0)break;//否
else if(p==1)break;//是
else inputworry();//不符要求
}
if(p==0)break;//成功的
}
else inputworry();
}
if(fff){
guodu();
}
//输入输出选择
system("cls");
while(fff){
int z=choose();
if(z==-1)fff=0;
else if(z==0)inputworry();
printf("\t\t-----------------------------------------\n");
printf("\t\t*****PS.按任意键退出这个观察区***********\n");
getchar();
system("cls");
//getchar();
}
}
bye();
return 0;
}