BFS求最短路:Penguins

题目链接:https://ac.nowcoder.com/acm/contest/11253/I

题目:

现有一个 20 * 41 的矩阵 , 第 21 列被阻挡住了,不能走。 现在给你两个人,一个人在 (20,20)的位置,它只能走左半部分的(20 * 20),一个人在(20,1)的位置,它只能走右半部分的位置。左边的人要走到(1,20)的位置, 右边的人要走到(1,22)的位置。

现在对他们两个走的方式进行了限制

以左边人走的方向为基准。 

左边人a,右边人b

a往左走, b则往右走。

a往右走,b则往左走。

a往上走,b则往上走。

a往下走,b则往下走。

同时还要注意,此题走的方向要用字典序最小情况:要求(D<L<R<U).

求同时到达指定地点的 最短路径。以左边人为基准的走的方式,然后把走过的路径修改为'A',输出两个数组。

输入:

 注意:中间第21列为空格隔开,代表左边不能走到右边,右边不能走到左边。

 第一行输出最短步数,

第二行输出走的路径,

第三行输出修改后数组的情况。

 思路:

此题是一道bfs的题目,首先存好对应的数组情况,并给它的四周赋值为'#'代表不能过去。

然后设置好四个方向走时对应的数组。以及方向后。进行bfs.

使用bfs由某个点到另一个点的过程中,要判断这个新的点之前是否走过了,使用一个choose[][][][]四维数组标记某个点是否走过,走了了就不用走,直接continue.

同时还要判断是否某个人被挡住了。如果某个人这个点被挡住了而另一个人没被挡住,则这个被挡住的人节点不变,没被挡住的人节点改变。

如果两个人都被挡住了,continue即可。

同时使用一个path[][][][]数组统计其前一个节点的四个坐标。后面修改路径'A'的时候要用。同时输出路径方向的时候要用

最后还有一个数组 f2[][][][]用来统计由前一个点到这个点的放下,是向上,想左,还是向右...

同时由后往前推里出了路径,所以我们用一个栈先把路径存下,然后先进后出,得到的就是从出发点到终点的路径过程。

代码实现: 

# include <iostream>
# include <queue>
# include <stack>
using namespace std;
 
const int N = 25;
 
char ch1[N][N],ch2[N][N];
 
bool choose[N][N][N][N];  // 最主要的是这里,标记用一个四维进行标记而不是两维进行标记

// 走的顺序是有规定的,因为D < L < R < U.所以我们要走的时候,应该按照这样的顺序。能先往D就先往D走,以此类推。

int x1[4] = {1,0,0,-1}; // 下,左,右,上
int y1[4] = {0,-1,1,0};
 
int x2[4] = {1,0,0,-1}; // 下,右,左,上
int y2[4] = {0,1,-1,0};
 
char f[4] = {'D','L','R','U'};

 
struct node
{
    int lx1,ly1,lx2,ly2;  // 两企鹅的坐标
    int cnt; // 当前走过的步数
};
 
struct node path[N][N][N][N]; // path[i][j][k][d] 存的就是走到这个节点的上一个节点
int f2[N][N][N][N]; // f2[i][j][k][d]存的就是上一个节点走到这个节点的方向
 
queue <node> q;
 
stack<int> st;
 
void print(int lx1 ,int ly1 , int lx2 ,int ly2) // 打印路径和修改数组值
{
    int tempx1 = lx1, tempy1 = ly1 , tempx2 = lx2 , tempy2 = ly2;
    while(tempx1 != 20 || tempy1 != 20 || tempx2 != 20 || tempy2 != 1)
    {
        ch1[tempx1][tempy1] = 'A';
        ch2[tempx2][tempy2] = 'A';
         
        st.push(f2[tempx1][tempy1][tempx2][tempy2]);
         
        struct node temp3 = path[tempx1][tempy1][tempx2][tempy2];
        tempx1 = temp3.lx1;
        tempy1 = temp3.ly1;
        tempx2 = temp3.lx2;
        tempy2 = temp3.ly2;
    }
    while(st.size())
    {
        printf("%c",f[st.top()]);
        st.pop();
    }
    printf("\n");
    ch1[20][20] = 'A';
    ch2[20][1] = 'A';
    for(int i = 1 ; i <= 20 ; i++)
    {
        for(int j = 1 ; j <= 20 ; j++)
        {
            printf("%c",ch1[i][j]);
        }
        printf(" ");
        for(int j = 1 ; j <= 20 ; j++)
        {
            printf("%c",ch2[i][j]);
        }
        printf("\n");
    }
}
 
void bfs()
{
    q.push({20,20,20,1,0});
    while(q.size())
    {
         struct node t = q.front() ;
        q.pop();
         
         
        int lx1 = t.lx1;
        int ly1 = t.ly1;
        int lx2 = t.lx2;
        int ly2 = t.ly2;
         
        int stp = t.cnt;
         
        if(lx1 == 1 && ly1 == 20 && lx2 == 1 && ly2 == 1) //到达了终点了
        {
            printf("%d\n",stp);
             
            print(lx1,ly1,lx2,ly2);
             
            return;
        }
        else
        {
            for(int i = 0 ; i < 4 ; i++) // 两个企鹅向四个方向出发
            {
                int newlx1 = lx1 + x1[i];
                int newly1 = ly1 + y1[i];
                int newlx2 = lx2 + x2[i];
                int newly2 = ly2 + y2[i];
                if(ch1[newlx1][newly1] == '#' && ch2[newlx2][newly2] == '#')
                {
                    continue;
                }
                if(ch1[newlx1][newly1] == '#' && ch2[newlx2][newly2] != '#')
                {
                    if(choose[lx1][ly1][newlx2][newly2]) // 如果已经走过了的话
                    {
                        continue;
                    }
                    choose[lx1][ly1][newlx2][newly2] = true;
                     
                    path[lx1][ly1][newlx2][newly2] = {lx1,ly1,lx2,ly2,stp};
                    f2[lx1][ly1][newlx2][newly2] = i;
                     
                    q.push({lx1,ly1,newlx2,newly2,stp + 1});
                }
                else if(ch1[newlx1][newly1] != '#' && ch2[newlx2][newly2] == '#')
                {
                    if(choose[newlx1][newly1][lx2][ly2])
                    {
                        continue;
                    }
                    choose[newlx1][newly1][lx2][ly2] = true;
                     
                    path[newlx1][newly1][lx2][ly2] = {lx1,ly1,lx2,ly2,stp};
                    f2[newlx1][newly1][lx2][ly2] = i;
                     
                    q.push({newlx1,newly1,lx2,ly2,stp + 1});
                }
                else
                {
                    if(choose[newlx1][newly1][newlx2][newly2])
                    {
                        continue;
                    }
                    choose[newlx1][newly1][newlx2][newly2] = true;
                     
                    path[newlx1][newly1][newlx2][newly2] = {lx1,ly1,lx2,ly2,stp};
                    f2[newlx1][newly1][newlx2][newly2] = i;
                     
                    q.push({newlx1,newly1,newlx2,newly2,stp + 1});
                }
            }
        }
         
    }
}
 
int main()
{
    for(int i = 0 ; i < 25 ; i++)
    {
        ch1[0][i] = '#';
        ch2[0][i] = '#';
        ch1[i][0] = '#';
        ch2[i][0] = '#';
        ch1[21][i] = '#';
        ch2[21][i] = '#';
        ch1[i][21] = '#';
        ch2[i][21] = '#';
    }
     
    for(int i = 1 ; i <= 20 ; i++)
    {
        for(int j = 1 ; j <= 20 ; j++)
        {
            cin >> ch1[i][j];
        }
        for(int j = 1 ; j <= 20 ; j++)
        {
            cin >> ch2[i][j];
        }
    }
     
    choose[20][20][20][1] = true;
     
    bfs();
     
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值