5978 Problem F 【递归入门】走迷宫

问题 F: 【递归入门】走迷宫
时间限制: 1 Sec 内存限制: 128 MB
提交: 128 解决: 46

题目描述
  有一个n*m格的迷宫(表示有n行、m列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这n*m个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-l表示无路)。
  请统一用 左上右下的顺序拓展,也就是 (0,-1),(-1,0),(0,1),(1,0)

输入
第一行是两个数n,m( 1 < n , m < 15 ),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。

输出
  所有可行的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示方向。
  如果没有一条可行的路则输出-1。

样例输入
5 6
1 0 0 1 0 1
1 1 1 1 1 1
0 0 1 1 1 0
1 1 1 1 1 0
1 1 1 0 1 1
1 1
5 6

样例输出
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)

提示
【算法分析】
  用一个a数组来存放迷宫可走的情况,另外用一个数组b来存放哪些点走过了。每个点用两个数字来描述,一个表示行号,另一个表示列号。对于某一个点(x,y),四个可能走的方向的点描述如下表:
   2

1  x,y  3

   4
  对应的位置为:(x, y-1),(x-1, y),(x, y+1),(x+1, y)。所以每个点都要试探四个方向,如果没有走过(数组b相应的点的值为0)且可以走(数组a相应点的值为1)同时不越界,就走过去,再看有没有到达终点,到了终点则输出所走的路,否则继续走下去。

这个查找过程用search来描述如下:

procedure search(x, y, b, p);{x,y表示某一个点,b是已经过的点的情况,p是已走过的路}

 begin
   for i:=1 to 4 do{分别对4个点进行试探}
   begin
     先记住当前点的位置,已走过的情况和走过的路;
     
     如果第i个点(xl,y1)可以走,则走过去;

     如果已达终点,则输出所走的路径并置有路可走的信息,

     否则继续从新的点往下查找search(xl,y1,b1,p1);
   end;
 end;
  有些情况很明显是无解的,如从起点到终点的矩形中有一行或一列都是为0的,明显道路不通,对于这种情况要很快地“剪掉”多余分枝得出结论,这就是搜索里所说的“剪枝”。从起点开始往下的一层层的结点,看起来如同树枝一样,对于其中的“枯枝”——明显无用的节点可以先行“剪掉”,从而提高搜索速度。

经验总结
这题有坑!!上面加粗的那一句话,就是坑人的,这题不需要提示中所谓的剪枝,如果真这么剪枝了,那就没法做对了,原因如下:
如果输入数据:
4 4
0 1 0 0
0 1 0 0
0 1 0 1
0 1 1 1
1 2
3 4
从起点(1,2)到终点(3,4)的矩形为:
1 0 0
1 0 0
1 0 1
很明显,有一列为0,但是,这个迷宫无解吗?
并不是,(1,2)->(2,2)->(3,2)->(4,2)->(4,3)->(4,4)->(3,4)即为唯一解。
所以,请不要加提示所说的剪枝,除此之外,注意无解输出-1的特判,其他的问题就不大啦~~
总结完毕 (ฅ´ω`ฅ)
emmmm经过前几个程序的历练,写非递归不是那么头疼啦!开心!!
非递归提升的方法,就是要自己写,千万别看别人的代码,一点点的总结,才能逐渐的进步♪(^∀^●)ノ

递归代码

#include <cstdio>
using namespace std;
int m,n,last_x,last_y,start_x,start_y;
int atlas[20][20];
bool flag[20][20]={false};
int direct[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
int index,count;
int answer[250][2];
bool judge(int x,int y)
{
    if(x==0||y==0||y>n||x>m)
        return false;
    if(atlas[x][y]==0||flag[x][y]==true)
        return false;
    return true;
}
void dispose(int x,int y,int index)
{
    if(x==last_x&&y==last_y)
    {
        for(int i=0;i<index;i++)
        {
            if(i!=index-1)
                printf("(%d,%d)->",answer[i][0],answer[i][1]);
            else
                printf("(%d,%d)\n",answer[i][0],answer[i][1]);
        }
        count++;
        return ;
    }
    for(int i=0;i<4;i++)
    {
        int new_x=x+direct[i][0];
        int new_y=y+direct[i][1];
        if(judge(new_x,new_y))
        {
            flag[new_x][new_y]=true;
            answer[index][0]=new_x;
            answer[index][1]=new_y;
            dispose(new_x,new_y,index+1);
            flag[new_x][new_y]=false;
        }
    }
}
int main()
{
    while(~scanf("%d %d",&m,&n))
    {
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&atlas[i][j]);
                flag[i][j]=false;
            }
        }
        scanf("%d %d",&start_x,&start_y);
        scanf("%d %d",&last_x,&last_y);
        index=0;
        count=0;
        if(judge(start_x,start_y))
        {
            flag[start_x][start_y]=true;
            answer[index][0]=start_x;
            answer[index][1]=start_y;
            dispose(start_x,start_y,index+1);
            if(count==0)
            {
                printf("-1\n");
            }
        }
        else
        {
            printf("-1\n");
        }
    }
    return 0;
}

非递归代码

#include <cstdio>
#include <stack>
using namespace std;

int m,n,last_x,last_y,start_x,start_y;
int atlas[20][20];
bool flag[20][20]={false};
bool tflag[20][20][4]={false};
int direct[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
int count;
int answer[250][2];
struct node
{
    int number,x,y,type;
};
bool judge(int x,int y)
{
    if(x==0||y==0||y>n||x>m)
        return false;
    if(atlas[x][y]==0||flag[x][y]==true)
        return false;
    return true;
}
void dispose()
{
    stack<node *> process;
    bool pflag=false;
    node *p=new node();
    p->number=0;
    p->x=start_x;
    p->y=start_y;
    p->type=0;
    flag[start_x][start_y]=true;
    answer[p->number][0]=start_x;
    answer[p->number][1]=start_y;
    process.push(p);
    while(!process.empty())
    {
        node *top=process.top();
        if(top->x==last_x&&top->y==last_y)
        {
            for(int i=0;i<=top->number;i++)
            {
                if(i==top->number)
                {
                    printf("(%d,%d)\n",answer[i][0],answer[i][1]);
                }
                else
                {
                    printf("(%d,%d)->",answer[i][0],answer[i][1]);
                }
            }
            count++;
            pflag=true;
        }
        if(pflag==true)
        {
            flag[top->x][top->y]=false;
            for(int i=0;i<4;i++)
                tflag[top->x][top->y][i]=false;
            process.pop();
            pflag=false;
            continue;
        }
        int f=0;
        for(int i=0;i<4;i++)
        {
            int new_x=top->x+direct[i][0];
            int new_y=top->y+direct[i][1];
            if(judge(new_x,new_y)&&tflag[top->x][top->y][i]==false)
            {
                tflag[top->x][top->y][i]=true;
                node *temp=new node();
                temp->number=top->number+1;
                temp->x=new_x;
                temp->y=new_y;
                temp->type=i;
                flag[new_x][new_y]=true;
                answer[temp->number][0]=new_x;
                answer[temp->number][1]=new_y;
                process.push(temp);
                f=1;
                break;
            }
        }
        if(f==0)
        {
            pflag=true;
        }
    }
} 
int main()
{
    while(~scanf("%d %d",&m,&n))
    {
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%d",&atlas[i][j]);
                flag[i][j]=false;
                for(int k=0;k<4;k++)
                    tflag[i][j][k]=false;
            }
        }
        scanf("%d %d",&start_x,&start_y);
        scanf("%d %d",&last_x,&last_y);
        count=0;
        if(judge(start_x,start_y))
        {
            dispose();
            if(count==0)
            {
                printf("-1\n");
            }
        }
        else
        {
            printf("-1\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a845717607/article/details/81324163