1. 程式人生 > 其它 >牛客多校2021(二)I.Penguins(BFS)

牛客多校2021(二)I.Penguins(BFS)

  • 題目:Penguins

  • 題意:給出兩張20 * 20的地圖,起點1為(20, 20),起點2為(20, 1),終點1為(1, 20),終點2為(1, 1),兩個企鵝需要分別從起點1->終點1、起點2->終點2,若企鵝1向上或向下走,企鵝2執行相同操作,若企鵝1向左或向右走,則企鵝2執行相反操作,求企鵝1到達終點1且企鵝同時到達終點2的最短路徑(若存在多條最短路徑,則輸出字典序最小的路徑),並將每次操作方向、以及走過的路徑輸出(將這兩張圖輸出即可,只需要將走過的路徑標記為'A')。
  • 解析:這道題思路很顯然用廣搜,首先需要開一個四維陣列(或結構體)記錄兩個企鵝的位置,按照"D、L、R、U"的順序進行廣搜, 每次搜到下一個結點位置則記錄其上一個結點位置,並記錄到下一個結點
    所進行的操作(下、左、右、上),這個記錄必須記錄在下一個結點的資訊上,若記錄在當前結點資訊上則會被不斷的更新覆蓋,最後無法通過遞迴的方式去查詢路徑。
    ps:若其中一隻企鵝下一個結點無法到達(碰牆、碰障礙)則需要讓其回到原來位置(或者說是原地不動),另一隻企鵝可以繼續其操作。
  • 程式碼:
#include<iostream>
#include<cstdio>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 25;
char g1[N][N], g2[N][N];
int dir[4][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};
int step = 0;
char op[10] = {'D', 'L', 'R', 'U'};
char p[N][N][N][N]; //記錄該位置
char path[10005];
struct Node
{
    int x1, y1, x2, y2;
};
Node pre_node[N][N][N][N]; //該位置上一個點的位置
int dis[N][N][N][N];

bool check1(int x, int y)
{
    if(g1[x][y] == '#' || x < 1 || x > 20 || y < 1 || y > 20) return true;
    return false;
}

bool check2(int x, int y)
{
    if(g2[x][y] == '#' || x < 1 || x > 20 || y < 1 || y > 20) return true;
    return false;
}

void bfs()
{
    queue<Node> q;
    q.push({20, 20, 20, 1});
    dis[20][20][20][1] = 0;
    while(q.size())
    {
        Node t = q.front();
        q.pop();
        if(t.x1 == 1 && t.y1 == 20 && t.x2 == 1 && t.y2 == 1) return;
        for(int i = 0; i < 4; i++)
        {
            int xx1 = t.x1 + dir[i][0], yy1 = t.y1 + dir[i][1];
            if(check1(xx1, yy1)) //碰牆或者遇到障礙
            {
                xx1 -= dir[i][0];
                yy1 -= dir[i][1];
            }
            int xx2 = t.x2 + dir[i][0], yy2 = t.y2 - dir[i][1]; //xx2座標與xx1座標變換相同但yy2需要與yy1操作相反
            if(check2(xx2, yy2)) //碰牆或者遇到障礙
            {
                xx2 -= dir[i][0];
                yy2 += dir[i][1];
            }
            if(dis[xx1][yy1][xx2][yy2] == -1) //之前未訪問過(保證是最短路徑)
            {
                pre_node[xx1][yy1][xx2][yy2] = {t.x1, t.y1, t.x2, t.y2};
                dis[xx1][yy1][xx2][yy2] = dis[t.x1][t.y1][t.x2][t.y2] + 1; //記錄當前路徑長度
                p[xx1][yy1][xx2][yy2] = op[i]; //記錄方向
                q.push({xx1, yy1, xx2, yy2});
            }
        }
    }
}

void find_Path(int x1, int y1, int x2, int y2)
{
    g1[x1][y1] = 'A', g2[x2][y2] = 'A';
    if(x1 == 20 && y1 == 20 && x2 == 20 && y2 == 1) return;
    int xx1 = pre_node[x1][y1][x2][y2].x1;
    int yy1 = pre_node[x1][y1][x2][y2].y1;
    int xx2 = pre_node[x1][y1][x2][y2].x2;
    int yy2 = pre_node[x1][y1][x2][y2].y2;
    find_Path(xx1, yy1, xx2, yy2);
    path[step++] = p[x1][y1][x2][y2];
}

int main()
{
    memset(dis, -1, sizeof dis);
    for(int i = 1; i <= 20; i++) scanf("%s%s", g1[i] + 1, g2[i] + 1);
    bfs();
    find_Path(1, 20, 1, 1); //從終點遞迴尋找路徑
    printf("%d\n%s\n", step, path);
    for(int i = 1; i <= 20; i++)
        printf("%s %s\n", g1[i] + 1, g2[i] + 1);
    return 0;
}