문제 링크

판을 뒤섞을 수 있다는 문제의 조건을 읽지 않아 푸는데 오래걸렸다..

문제를 풀때는 문제를 잘 읽어야 한다

다른 사람의 풀이의 좋은 아이디어

  • 12345로 구성된 판과 역순의 54321로 구성된 경로의 판의 최단거리는 같다는 점을 이용해 중복된 검사를 하지 않도록 하였다.
  • 출구에서 나갈 수 없으면 경로를 확인하지 않음
  • 최소값이 12임을 활용하여 12가 나오면 더이상 검사하지 않음
  • 입구에서 들어 갈 수 없으면 경로를 확인하지 않음
  • 판의 순서와 역순의 기록한 중복확인용 다차원 배열
  • 5!의 순열을 저장한 다차원 배열(좋은 것 같지는 않다.)

내 풀이

#define _CRT_SECURE_NO_WARNINGS

#include <ctime>
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>

using namespace std;

static int INF = 987654321;
int maze[7][7][7], ori_maze[7][7][7];
int used[7], order[5];

struct pos
{
    int x, y, z, mv;
};

void rotate(int idx)
{
    int t[5][5];
    for (int y = 0; y < 5; y++)
        for (int x = 0; x < 5; x++)
            t[x][4 - y] = maze[idx][y + 1][x + 1];
    for (int y = 0; y < 5; y++)
        for (int x = 0; x < 5; x++)
            maze[idx][y + 1][x + 1] = t[y][x];
}

int findWayOut()
{
    if (maze[1][1][1] == 0)
        return INF;
    // z, y, x
    int d[6][3] = { {1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1} };
    int fp[7][7][7];
    queue<pos> que;

    que.push({ 1, 1, 1, 0 });
    memset(fp, 0, sizeof(fp));

    fp[1][1][1] = 1;

    while (!que.empty())
    {
        pos fr = que.front();
        que.pop();
        if (fr.x == 5 && fr.y == 5 && fr.z == 5)
            return fr.mv;

        for (int i = 0; i < 6; i++)
        {
            pos n = fr;
            n.z += d[i][0];
            n.y += d[i][1];
            n.x += d[i][2];
            n.mv += 1;
            if (!maze[n.z][n.y][n.x] || fp[n.z][n.y][n.x])
                continue;

            fp[n.z][n.y][n.x] = 1;
            que.push(n);
        }
    }

    return INF;
}

int permu(int idx)
{
    if (idx == 6)
    {
        return findWayOut();
    }

    int ret = INF, n = 4;
    while (n)
    {
        int t = permu(idx + 1);
        rotate(idx);
        ret = min(t, ret);

        n -= 1;
    }


    rotate(idx);

    return ret;
}

int boardPermu(int idx)
{
    if (idx == 5)
    {
        for (int i = 0; i < 5; i++)
        {
            memcpy(maze[i + 1], ori_maze[order[i]], sizeof(ori_maze[0]));
        }
        return permu(1);
    }
    int ret = INF;
    for (int i = 1; i <= 5; i++)
    {
        if (used[i])
            continue;
        used[i] = 1;
        order[idx] = i;
        ret = min(ret, boardPermu(idx + 1));
        if (ret == 12)
            return ret;
        used[i] = 0;
    }

    return ret;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    //test
    clock_t st, ed;

    for (int z = 1; z <= 5; z++)
    {
        for (int y = 1; y <= 5; y++)
        {
            for (int x = 1; x <= 5; x++)
            {
                cin >> ori_maze[z][y][x];
            }
        }
    }

    st = clock();

    int ans = boardPermu(0);

    if (ans == INF)
        cout << -1 << "\n";
    else
        cout << ans << "\n";

    ed = clock();

    cout << ed - st << "\n";

    return 0;
}

다른사람 풀이

#include <iostream>
#include <queue>
#include <cstring>

using namespace std;

int map[4][5][5][5];
int panorder[120][5]; // [5]에 들어가는 값의 범위는 1 ~ 5, 120 5!
int pan[5][5][5][5][5]; //판 중복 체크(입구->출구 == 출구->입구)
int pcnt;
int vis[5];
int chc[5];
int ro[5];
int best = -1;
int qcheck[5][5][5];

struct coor {
    int x;
    int y;
    int z;
    int d;
};

queue<coor> q;
int dx[6] = { 1,0,0,-1,0,0 };
int dy[6] = { 0,1,0,0,-1,0 };
int dz[6] = { 0,0,1,0,0,-1 };

void dfs(int pos) {
    if (pos == 5) {
        for (int i = 0; i < 5; i++)
            panorder[pcnt][i] = vis[i] - 1;
        pcnt++;
        return;
    }
    for (int i = 1; i <= 5; i++) {
        if (chc[i] != 0)
            continue;
        vis[pos] = i;
        chc[i] = 1;
        dfs(pos + 1);
        vis[pos] = 0;
        chc[i] = 0;
    }
}

void bfs(int dfsnumber) {
    memset(qcheck, 0, sizeof(qcheck));
    int x, y, z, nx, ny, nz, d;
    q.push({ 0,0,0,0 });
    qcheck[0][0][0] = 1;
    while (!q.empty()) {
        x = q.front().x;
        y = q.front().y;
        z = q.front().z;
        d = q.front().d;
        q.pop();
        if (x == 4 && y == 4 && z == 4) {
            if (best == -1 || (best != -1 && best > d)) {
                best = d;
                if (d == 12) return;
            }
        }
        if (best != -1 && d + 1 >= best) continue;
        for (int i = 0; i < 6; i++) {
            nx = x + dx[i];
            ny = y + dy[i];
            nz = z + dz[i];
            if (nx < 0 || ny < 0 || nz < 0 || nx >= 5 || ny >= 5 || nz >= 5) continue;
            if (qcheck[nz][ny][nx] == 1 || map[ro[nz]][panorder[dfsnumber][nz]][ny][nx] == 0) continue;
            qcheck[nz][ny][nx] = 1;
            q.push({ nx,ny,nz,d + 1 });
        }
    }
}

int main(void) {
    for (int i = 0; i < 5; i++)
        for (int j = 0; j < 5; j++)
            for (int k = 0; k < 5; k++)
                cin >> map[0][i][j][k];

    // map[회전][판][행][열]
    // map[0] : 0회전,  map[1] : 1회전, map[2] : 2회전
    for (int i = 1; i <= 3; i++) {
        for (int j = 0; j < 5; j++) {
            for (int k = 0; k < 5; k++) {
                for (int g = 0; g < 5; g++) {
                    map[i][j][4 - g][k] = map[i - 1][j][k][g];
                }
            }
        }
    }
    dfs(0); // set panoder 12345 ~ 54321

    for (int i = 0; i < pcnt; i++) {
        if (pan[panorder[i][0]][panorder[i][1]][panorder[i][2]][panorder[i][3]][panorder[i][4]] == 0) {
            pan[panorder[i][0]][panorder[i][1]][panorder[i][2]][panorder[i][3]][panorder[i][4]] = 1; // 입구 -> 출구
            pan[panorder[i][4]][panorder[i][3]][panorder[i][2]][panorder[i][1]][panorder[i][0]] = 1; // 출구 -> 입구
            for (int fiv = 0; fiv < 4; fiv++) {
                ro[4] = fiv;
                // 출구 막힘
                if (map[ro[4]][panorder[i][4]][4][4] == 0) continue;

                for (int one = 0; one < 4; one++) {
                    ro[0] = one;
                    // 입구 막힘
                    if (map[ro[0]][panorder[i][0]][0][0] == 0) continue;

                    for (int two = 0; two < 4; two++) {
                        ro[1] = two;
                        for (int thr = 0; thr < 4; thr++) {
                            ro[2] = thr;
                            for (int fou = 0; fou < 4; fou++) {
                                ro[3] = fou;
                                bfs(i);
                                if (best == 12) {
                                    cout << best;
                                    return 0;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    cout << best;
}

댓글남기기