迷宫问题,c/c++ 各显身手

c 解迷宫示例代码:

#include <stdio.h>
#include <stdlib.h>

#define row 15
#define column 21
#define Max 500
typedef struct{
    int x,y;           /*搜索位置的坐标 */
    int pre;           /*表示前驱点的位置索引 */
}Footprint;
typedef struct{
    int i,j; /*4个搜索方向的坐标变化值 */
}Direction;
int maze[row+2][column+2]= /* 定义四周为墙。故为row+2,column+2, 0 为通路,1为墙 */
{
    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1},
    {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1},
    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
};
    Footprint foots[Max];
// 左右上下,注意,此处列值移动为左右,行值移动为上下,直接与MAZE 数组下标运算
Direction Direct[4]={{0,-1},{0,1},{-1,0},{1,0}};   
void print_result(int tail)
{
    int i,j,k;
    k=tail;
   
    do
    {
        i=foots[k].x; j=foots[k].y;
        maze[i][j]=3;
        k=foots[k].pre;        // 由后继找到它的前趋。
    }while(k);
/*   
    for(i=1;i<=k;i++)
    {
        maze[foots[i].x][foots[i].y]=3;
    }
*/
    printf("模拟迷宫路径: @ 表示最后走出迷宫的路径, -1表示探索过的路径/n");
    printf("进入->/n");
    for (i=1;i<=row;i++)
    {
        for (j=1;j<=column;j++)
        {
            if (maze[i][j]==3) printf("%2c",'@');
            else printf("%2d",maze[i][j]);
        }
        if (i==row) printf("->走出/n/n");
        else printf("/n");
    }
}
void main(void)
{
    int i,j,k,newi,newj,QueueHead,QueueTail;
    int Gotit=0;
    QueueHead=0;QueueTail=1; //ensure foots[0] is 0
    foots[QueueTail].x=1;foots[QueueTail].y=1;foots[QueueTail].pre=0; maze[1][1]=-1; //入口入队列(1,1)
    do {
        QueueHead++; i=foots[QueueHead].x; j=foots[QueueHead].y; /*下一步出队列  */
        if(i==15&& j==18)
        {
            printf("%d,%d/n",i,j);
        }

        for (k=0;k<4;k++){         /*沿4个方向搜索*/
            newi=i+Direct[k].i; newj=j+Direct[k].j;  /*确定新的搜索位置 */
           
            if (!maze[newi][newj]) {          /*如果新位置是未搜索通道,则将新位置入队列*/
                QueueTail++; foots[QueueTail].x=newi;foots[QueueTail].y=newj;
                foots[QueueTail].pre=QueueHead; // 标识新结点的前趋
                maze[newi][newj]=-1; /*标识搜索过的位置为-1 来了就算搜索过*/
            }
            if (newi==row && newj==column){          /*找到出口*/
                print_result(QueueTail); Gotit=1;
                break; // pay attention
            }
        }
    }while(QueueHead<QueueTail); // 未搜索完,继续
    if (!Gotit) printf("No Pass!/n");
    system("pause");
}

注意:如果找到了出口,继续搜索却找不到所有路径
因为搜索互相堵路了。 是不是只能有深度搜索才能找到全路径呢?

-------------------------------------------------------------------------------------------------------

c++ 的示例代码:

#include<iostream.h>

#define up     1
#define down   2
#define left   3
#define right  4  
#define wrong    0

int in_a,in_b;//定义入口
int out_a,out_b;//定义出口
int direction;//定义一个方向向量
int Width=0;
int Height=0;

/*
      direction=2-->从上向下进行宽度遍历
      direction=1-->从下向上进行宽度遍历
      direction=4-->从左向右进行宽度遍历
      direction=3-->从右向左进行宽度遍历
*/


/**********成员函数声明**********/
void printf(int **x,int Hei,int Wid);//输出二维数组
int  GetDirection(int a,int b);//得到一个宽度遍历迷宫图的方向
void visit(int a,int b,int **m,int **v);//访问单个结点,a,b,表示结点坐标
void search(int direction,int **m,int **v);//宽度遍历整个迷宫
void back_check(int **m,int **v,int in_a,int in_b);//处理意外情况
void outputpath(int **v,int in_a,int in_b);//输出最短路径



void main()
{
    cout<<"请输入迷宫尺寸大小:"<<endl;
    cout<<"宽:";
    cin>>Width;
    cout<<"高:";
    cin>>Height;
    int key=1;
    while(key==1){
        int **value=new int*[Height];//动态创建迷宫路径矩阵
        for(int y=0;y<Height;y++)
            value[y]=new int[Width];

        for(int k=0;k<Height;k++){//初始化迷宫路径矩阵
            for(int t=0;t<Width;t++)
                value[k][t]=0;
        }

        int **maze=new int*[Height];  
        for(int i=0;i<Height;i++)//动态创建迷宫矩阵
            maze[i]=new int[Width];  

        cout<<"请输入迷宫矩阵,0代表路径,1代表障碍!"<<endl;
        for(int count=0;count<Height;count++){
            for(int j=0;j<Width;j++)
                cin>>maze[count][j];
        }
 
        int a,b;
        cout<<"请输入入口地址:";
        cin>>a>>b;//初始化入口
        in_a=a-1;
        in_b=b-1;
        cout<<"请输入出口地址:";
        cin>>a>>b;//初始化出口
        out_a=a-1;
        out_b=b-1;

        direction=GetDirection(out_a,out_b);//根据出口得到方向向量
        value[out_a][out_b]=1;//从出口开始遍历,初始化为1

        search(direction,maze,value);
        back_check(maze,value,in_a,in_b);


        cout<<"该迷宫用0,1矩阵表示为:"<<endl;
        printf(maze,Height,Width);
        cout<<"迷宫入口为:"<<'('<<in_a+1<<','<<in_b+1<<')'<<endl;
        cout<<"迷宫出口为:"<<'('<<out_a+1<<','<<out_b+1<<')'<<endl;
        cout<<"路径矩阵表示为:"<<endl;
        printf(value,Height,Width);
        outputpath(value,in_a,in_b);
        cout<<"输入数字1继续,输入-1退出程序!"<<endl;
        cin>>key;
    }
}

void printf(int **x,int Hei,int Wid)
{
    int i=0;//记录行数
    while(i<Hei){
        for(int j=0;j<Wid;j++)
            cout<<x[i][j]<<',';
        cout<<endl;
        i++;
    }
}

int  GetDirection(int a,int b)
{
    if(a==0)          return down;
    if(a==Height-1)   return up;
    if(b==0)          return right;
    if(b==Width-1)    return left;
    return wrong
}

void visit(int a,int b,int **m,int **v)
{
    if(v[a][b]==0 || m[a][b]==1)
        return;//不访问无值结点和障碍物结点

    /********修改当前结点上方结点********/
    if(a-1>=0 && m[a-1][b]==0){//保证上方有结点且不是障碍物
        if(v[a-1][b]==0 || v[a][b]+1<v[a-1][b])
            v[a-1][b]=v[a][b]+1;
    }

    /********修改当前结点下方结点********/
    if(a+1<Height && m[a+1][b]==0){//保证下方有结点且不是障碍物
        if(v[a+1][b]==0 || v[a][b]+1<v[a+1][b])
            v[a+1][b]=v[a][b]+1;
    }

    /********修改当前结点左方结点********/
    if(b-1>=0 && m[a][b-1]==0){//保证左方有结点且不是障碍物
        if(v[a][b-1]==0 || v[a][b]+1<v[a][b-1])
            v[a][b-1]=v[a][b]+1;
    }

    /********修改当前结点右方结点********/
    if(b+1<Width && m[a][b+1]==0){//保证右方有结点且不是障碍物
        if(v[a][b+1]==0 || v[a][b]+1<v[a][b+1])
            v[a][b+1]=v[a][b]+1;
    }
   
}

void search(int direction,int **m,int **v)
{
    int count;//上下遍历时记录行数,左右遍历时记录列数

    /**********向下遍历整个图**********/
    if(direction==down){
        count=0;//记录行标
        while(count<Height){
            for(int i=0;i<Width;i++){//找到该行中第一个被访问过的点
                if(v[count][i]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向左遍历
                visit(count,j,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(count,k,m,v);
            count++;//进入下一行
        }
    }

    /**********向上遍历整个图**********/
    if(direction==up){
        count=Height-1;//记录行标
        while(count>=0){
            for(int i=0;i<Width;i++){//找到该行中第一个被访问过的点
                if(v[count][i]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向左遍历
                visit(count,j,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(count,k,m,v);
            count--;//进入上一行
        }
    }

    /**********向右遍历整个图**********/
    if(direction==right){
        count=0;//记录列标
        while(count<Width){
            for(int i=0;i<Height;i++){//找到该列中第一个被访问过的点
                if(v[i][count]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向上遍历
                visit(j,count,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(k,count,m,v);
            count++;//进入右一列
        }
    }

    /**********向左遍历整个图**********/
    if(direction==left){
        count=Width-1;//记录列标
        while(count>=0){
            for(int i=0;i<Height;i++){//找到该列中第一个被访问过的点
                if(v[i][count]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向上遍历
                visit(j,count,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(k,count,m,v);
            count--;//进入左一列
        }
    }
}

void back_check(int **m,int **v,int in_a,int in_b)//确保能够遍历到出口点
{
    int direction;
    if(v[in_a][in_b]==0){
        direction=up;
        search(direction,m,v);
        direction=down;
        search(direction,m,v);
        direction=left;
        search(direction,m,v);
        direction=right;
        search(direction,m,v);
    }
}

void outputpath(int **v,int in_a,int in_b)
{
    int a=in_a;
    int b=in_b;
    if(v[a][b]==0)
        cout<<"没有通往出口的最短路径!!!"<<endl;
    else{
        cout<<"走出该迷宫的最短路径为:"<<endl;
        while(v[a][b]!=1){
            cout<<'('<<a+1<<','<<b+1<<')'<<"-->";
            if(a-1>=0 && v[a-1][b]==v[a][b]-1){//上移
                a=a-1;
                continue;
            }
            if(a+1<Height && v[a+1][b]==v[a][b]-1){//下移
                a=a+1;
                continue;
            }
            if(b-1>=0 && v[a][b-1]==v[a][b]-1){//左移
                b=b-1;
                continue;
            }
            if(b+1<Width && v[a][b+1]==v[a][b]-1){//右移
                b=b+1;
                continue;
            }
        }
        cout<<'('<<a+1<<','<<b+1<<')'<<endl;
    }
}

----------------------------------------------------------------------------------------------

迷宫游戏:

#include<iostream.h>

#define up     1
#define down   2
#define left   3
#define right  4  
#define wrong    0

int in_a,in_b;//定义入口
int out_a,out_b;//定义出口
int direction;//定义一个方向向量
int Width=0;
int Height=0;

/*
      direction=2-->从上向下进行宽度遍历
      direction=1-->从下向上进行宽度遍历
      direction=4-->从左向右进行宽度遍历
      direction=3-->从右向左进行宽度遍历
*/


/**********成员函数声明**********/
void printf(int **x,int Hei,int Wid);//输出二维数组
int  GetDirection(int a,int b);//得到一个宽度遍历迷宫图的方向
void visit(int a,int b,int **m,int **v);//访问单个结点,a,b,表示结点坐标
void search(int direction,int **m,int **v);//宽度遍历整个迷宫
void back_check(int **m,int **v,int in_a,int in_b);//处理意外情况
void outputpath(int **v,int in_a,int in_b);//输出最短路径



void main()
{
    cout<<"请输入迷宫尺寸大小:"<<endl;
    cout<<"宽:";
    cin>>Width;
    cout<<"高:";
    cin>>Height;
    int key=1;
    while(key==1){
        int **value=new int*[Height];//动态创建迷宫路径矩阵
        for(int y=0;y<Height;y++)
            value[y]=new int[Width];

        for(int k=0;k<Height;k++){//初始化迷宫路径矩阵
            for(int t=0;t<Width;t++)
                value[k][t]=0;
        }

        int **maze=new int*[Height];  
        for(int i=0;i<Height;i++)//动态创建迷宫矩阵
            maze[i]=new int[Width];  

        cout<<"请输入迷宫矩阵,0代表路径,1代表障碍!"<<endl;
        for(int count=0;count<Height;count++){
            for(int j=0;j<Width;j++)
                cin>>maze[count][j];
        }
 
        int a,b;
        cout<<"请输入入口地址:";
        cin>>a>>b;//初始化入口
        in_a=a-1;
        in_b=b-1;
        cout<<"请输入出口地址:";
        cin>>a>>b;//初始化出口
        out_a=a-1;
        out_b=b-1;

        direction=GetDirection(out_a,out_b);//根据出口得到方向向量
        value[out_a][out_b]=1;//从出口开始遍历,初始化为1

        search(direction,maze,value);
        back_check(maze,value,in_a,in_b);


        cout<<"该迷宫用0,1矩阵表示为:"<<endl;
        printf(maze,Height,Width);
        cout<<"迷宫入口为:"<<'('<<in_a+1<<','<<in_b+1<<')'<<endl;
        cout<<"迷宫出口为:"<<'('<<out_a+1<<','<<out_b+1<<')'<<endl;
        cout<<"路径矩阵表示为:"<<endl;
        printf(value,Height,Width);
        outputpath(value,in_a,in_b);
        cout<<"输入数字1继续,输入-1退出程序!"<<endl;
        cin>>key;
    }
}

void printf(int **x,int Hei,int Wid)
{
    int i=0;//记录行数
    while(i<Hei){
        for(int j=0;j<Wid;j++)
            cout<<x[i][j]<<',';
        cout<<endl;
        i++;
    }
}

int  GetDirection(int a,int b)
{
    if(a==0)          return down;
    if(a==Height-1)   return up;
    if(b==0)          return right;
    if(b==Width-1)    return left;
    return wrong;
}

void visit(int a,int b,int **m,int **v)
{
    if(v[a][b]==0 || m[a][b]==1)
        return;//不访问无值结点和障碍物结点

    /********修改当前结点上方结点********/
    if(a-1>=0 && m[a-1][b]==0){//保证上方有结点且不是障碍物
        if(v[a-1][b]==0 || v[a][b]+1<v[a-1][b])
            v[a-1][b]=v[a][b]+1;
    }

    /********修改当前结点下方结点********/
    if(a+1<Height && m[a+1][b]==0){//保证下方有结点且不是障碍物
        if(v[a+1][b]==0 || v[a][b]+1<v[a+1][b])
            v[a+1][b]=v[a][b]+1;
    }

    /********修改当前结点左方结点********/
    if(b-1>=0 && m[a][b-1]==0){//保证左方有结点且不是障碍物
        if(v[a][b-1]==0 || v[a][b]+1<v[a][b-1])
            v[a][b-1]=v[a][b]+1;
    }

    /********修改当前结点右方结点********/
    if(b+1<Width && m[a][b+1]==0){//保证右方有结点且不是障碍物
        if(v[a][b+1]==0 || v[a][b]+1<v[a][b+1])
            v[a][b+1]=v[a][b]+1;
    }
   
}

void search(int direction,int **m,int **v)
{
    int count;//上下遍历时记录行数,左右遍历时记录列数

    /**********向下遍历整个图**********/
    if(direction==down){
        count=0;//记录行标
        while(count<Height){
            for(int i=0;i<Width;i++){//找到该行中第一个被访问过的点
                if(v[count][i]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向左遍历
                visit(count,j,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(count,k,m,v);
            count++;//进入下一行
        }
    }

    /**********向上遍历整个图**********/
    if(direction==up){
        count=Height-1;//记录行标
        while(count>=0){
            for(int i=0;i<Width;i++){//找到该行中第一个被访问过的点
                if(v[count][i]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向左遍历
                visit(count,j,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(count,k,m,v);
            count--;//进入上一行
        }
    }

    /**********向右遍历整个图**********/
    if(direction==right){
        count=0;//记录列标
        while(count<Width){
            for(int i=0;i<Height;i++){//找到该列中第一个被访问过的点
                if(v[i][count]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向上遍历
                visit(j,count,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(k,count,m,v);
            count++;//进入右一列
        }
    }

    /**********向左遍历整个图**********/
    if(direction==left){
        count=Width-1;//记录列标
        while(count>=0){
            for(int i=0;i<Height;i++){//找到该列中第一个被访问过的点
                if(v[i][count]!=0)
                    break;
            }
            for(int j=i;j>=0;j--)//以刚才找到的点为中心向上遍历
                visit(j,count,m,v);
            for(int k=i+1;k<Width;k++)//以刚才找到的点为中心向右遍历
                visit(k,count,m,v);
            count--;//进入左一列
        }
    }
}

void back_check(int **m,int **v,int in_a,int in_b)//确保能够遍历到出口点
{
    int direction;
    if(v[in_a][in_b]==0){
        direction=up;
        search(direction,m,v);
        direction=down;
        search(direction,m,v);
        direction=left;
        search(direction,m,v);
        direction=right;
        search(direction,m,v);
    }
}

void outputpath(int **v,int in_a,int in_b)
{
    int a=in_a;
    int b=in_b;
    if(v[a][b]==0)
        cout<<"没有通往出口的最短路径!!!"<<endl;
    else{
        cout<<"走出该迷宫的最短路径为:"<<endl;
        while(v[a][b]!=1){
            cout<<'('<<a+1<<','<<b+1<<')'<<"-->";
            if(a-1>=0 && v[a-1][b]==v[a][b]-1){//上移
                a=a-1;
                continue;
            }
            if(a+1<Height && v[a+1][b]==v[a][b]-1){//下移
                a=a+1;
                continue;
            }
            if(b-1>=0 && v[a][b-1]==v[a][b]-1){//左移
                b=b-1;
                continue;
            }
            if(b+1<Width && v[a][b+1]==v[a][b]-1){//右移
                b=b+1;
                continue;
            }
        }
        cout<<'('<<a+1<<','<<b+1<<')'<<endl;
    }
}

你可能感兴趣的:(迷宫问题,c/c++ 各显身手)