2017.8.1拼多多内推内推笔试题(4)—迷宫寻路(状态压缩+BFS)

题目要求
假设一个探险家被困在了地底的迷宫之中,要从当前位置开始找到一条通往迷宫出口的路径。迷宫可以用一个二维矩阵组成,有的部分是墙,有的部分是路。迷宫之中有的路上还有门,每扇门都在迷宫的某个地方有与之匹配的钥匙,只有先拿到钥匙才能打开门。请设计一个算法,帮助探险家找到脱困的最短路径。如前所述,迷宫是通过一个二维矩阵表示的,每个元素的值的含义如下 0-墙,1-路,2-探险家的起始位置,3-迷宫的出口,大写字母-门,小写字母-对应大写字母所代表的门的钥匙 。
输入描述
迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇。
输入例子
5 5
02111
01a0A
01003
01001
01111
输出例子
7
题目思路:
由于做这个题之前没了了解到BFS,所以赶快撸了一下课本,这里求最短距离,外加门的数量不超过10个,所以直接一个暴力BFS,又由于需要记录持有钥匙的状态,所以使用状态压缩用二进制数表示持有钥匙状态。
在BFS之前先给出初始状态设置,这里由于有一个钥匙的概念,所以问题变为如何在走的过程中记录钥匙信息,所以这里采用一个状态压缩法,用一个数来代表有没有某一把钥匙,即这个数的二进制表示时第i位为1代表有第a+i把钥匙,否则没有,相当于迷宫每一个点有1024个状态。
下面给出BFS实现代码:

int n,m,sx,sy,ex,ey;
char g[1024][1024];
int use[120][120][1400];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
struct node
{
    int x,y,k;
};

int bfs()
{
    memset(use,0xff,sizeof(use));
    queueq;
    node t;
    t.x=sx;
    t.y=sy;
    t.k=0;
    use[t.x][t.y][t.k]=0;
    q.push(t);
    while(!q.empty())
    {
        t = q.front();
        q.pop();
        //printf("%d %d %d %d\n",t.x,t.y,t.k,use[t.x][t.y][t.k]);
        if(t.x==ex&&t.y==ey) return use[t.x][t.y][t.k];
        for(int i=0;i<4;i++)//上下左右
        {
            node k;//分别往上下左右走
            k.x = t.x + dx[i];
            k.y = t.y + dy[i];
            k.k = t.k;
            if(k.x<0||k.x>=n||k.y<0||k.y>=m||g[k.x][k.y]=='0') continue;//直接进入下次循环
            if(g[k.x][k.y]>='a'&&g[k.x][k.y]<='z')
            {
                k.k = k.k|(1<<(g[k.x][k.y]-'a'));//走到钥匙点捡起钥匙
            }
            if(g[k.x][k.y]>='A'&&g[k.x][k.y]<='Z')
            {
                int p = k.k&(1<<(g[k.x][k.y]-'A'));//走到门处匹配钥匙
                if(p==0) continue;//没有钥匙直接进入下次循环
            }
            if(use[k.x][k.y][k.k]==-1||use[k.x][k.y][k.k]>use[t.x][t.y][t.k]+1)//第一个条    件保证BFS,第二个条件保证不走墙
            {
                use[k.x][k.y][k.k]=use[t.x][t.y][t.k]+1;
                q.push(k);
            }
        }
    }
    return -1;
}

有了BFS+状态压缩,写个主函数就可以直接AC了。
主函数

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i"%s",g[i]);
        for(int j=0;j<m;j++)
        {
            if(g[i][j]=='2') {sx=i;sy=j;}//储存起点
            if(g[i][j]=='3') {ex=i;ey=j;}//储存终点
        }
    }
    printf("%d\n",bfs());
    return 0;
}

你可能感兴趣的:(常用算法整理)