길민호(ethan.mino)
코딩수첩
길민호(ethan.mino)
전체 방문자
오늘
어제
  • 분류 전체보기 (215)
    • Computer Science (0)
    • Web (6)
      • CSS (0)
      • HTML (0)
    • Node.js (0)
    • Javascript (2)
    • Java (46)
      • Spring (27)
      • Jsp (0)
    • C\C++ (2)
    • Programming (0)
    • AI (0)
    • Database (7)
    • Git (5)
    • Algorithm (119)
      • Stack (0)
      • Queue (0)
      • Linked List (0)
      • Sort (0)
      • Simulation (27)
      • Recursion (0)
      • Backtracking (4)
      • Two Pointer (3)
      • Dynamic Programming (19)
      • Greedy (10)
      • Graph (3)
      • Dijkstra (1)
      • BFS\DFS (8)
      • Floyd (1)
      • MST (4)
      • Tree (4)
      • Binary Search (8)
      • Binary Search Tree (4)
    • IntelliJ (4)
    • Vscode (0)
    • Operating System (0)
    • 후기 (3)
    • 성장일지 (13)
    • 스터디 (7)
    • 설치 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • ㅡ

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
길민호(ethan.mino)

코딩수첩

Algorithm/Simulation

[백준 13460번] 구슬 탈출 2 (C/C++)

2022. 3. 20. 06:12

https://www.acmicpc.net/problem/13460

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net


구슬 탈출은 네 가지 동작을 최대 10번 수행하는 모든 경우의 수를 실행해보면 됩니다.

 

단, 먼저 경우의 수를 구하고, 각각의 경우의 수에 대해 수행하면, 가능한 경우의 수가 410이기 때문에 시간초과가 발생할 수 있습니다.

예를 들어, {위, 아래, 오른쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽}, {위, 아래, 오른쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽, 왼쪽} 두 가지 경우의 수가 있을 때, 각각의 경우의 수에 대해 독립적으로 실행할 경우 {위, 아래, 오른쪽, 왼쪽}이 중복되지만 다시 계산해야합니다.

하지만 백트래킹과 함께 사용하면, th번째 동작을 선택할 때, th-1째까지의 실행 결과를 유지하기 때문에 중복된 계산을 줄일 수 있어 시간을 단축시킬 수 있습니다.

 

아래는 전체 코드입니다. 

#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second

int n, m;
char board[10][10];

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, -1, 0, 1};

int tilt(char b[][10], int dir){
    int it; // 반복 횟수 (상/하 기울임인 경우 m번 반복, 우/좌 기울임인 경우 n번 반복)
    if(dir == 0 || dir == 2) it = m;  
    else it = n;

    bool escape[2] = {false, false};    // 구슬이 탈출했는지 나타내는 flag 배열 (0 : 빨간 구슬, 1 : 파란 구슬)
    for(int j = 0; j < it; j++){    // 
        pair<int, int> cur; // 검사 좌표
        if(dir == 0) cur = {1, j};  // 위쪽 기울임인 경우 (위에서 부터 검사)
        else if(dir == 1) cur = {j, m - 2}; // 오른쪽 기울임인 경우
        else if(dir == 2) cur = {n - 2, j}; // 아래쪽 기울임인 경우
        else cur = {j, 1};  // 왼쪽 기울임인 경우
        
        while(true){    // 구슬을 만날 때까지 기울임 반대 방향으로 이동
            // 검사 좌표가 게임판을 벗어나는 경우
            if(cur.x < 0 || cur.y < 0 || cur.x >= n || cur.y >= m) break;   

            if(b[cur.x][cur.y] == 'R' || b[cur.x][cur.y] == 'B'){   // 검사하는 좌표에 구슬이 있는 경우
                pair<int, int> marble = {cur.x, cur.y}; // 구슬의 좌표

                while(true){    // 구슬을 기울임 방향으로 이동시킴
                    pair<int, int> nx = {marble.x+dx[(dir+2)%4],marble.y+dy[(dir+2)%4]};    // 구슬의 이동할 좌표

                    // 구슬이 이동할 위치가 벽이거나, 구슬인 경우 더이상 이동하지 않음
                    if(b[nx.x][nx.y] == '#' || b[nx.x][nx.y] == 'R' || b[nx.x][nx.y] == 'B') break; 
                    else if (b[nx.x][nx.y] == 'O'){ // 구슬이 이동할 위치가 구멍인 경우
                        // 빨간 구슬인 경우 0을 true로, 파란 구슬인 경우 1을 true로 set
                        if(b[marble.x][marble.y] == 'R') escape[0] = true;  
                        else escape[1] = true;

                        // 구슬이 빠져나가므로 구슬의 위치를 '.'으로 변경
                        b[marble.x][marble.y] = '.';    
                        break;  // 더이상 구슬을 이동시키지 않음
                    }else{  // 빈 칸인 경우
                        b[nx.x][nx.y] = b[marble.x][marble.y];  // 구슬을 빈 칸으로 이동시킴
                        b[marble.x][marble.y] = '.';    // 구슬의 이전 위치는 빈 칸으로 만듦
                        marble = nx;    // 구슬을 이동시킴
                    }
                }
            }
            cur = {cur.x + dx[dir], cur.y + dy[dir]};   // 검사 좌표를 기울임 반대 방향으로 한 칸 이동시킴
        }
    }

    if(escape[1]) return -1;  // 파란 구슬이 탈출한 경우
    else if(escape[0]) return 1; // 빨간 구슬만 탈출한 경우
    else return 0; // 아무 구슬도 탈출하지 못한 경우
}

int ans = INT_MAX;
void c(char board[][10], int th){ // 보드를 기울이는 모든 경우의 수를 계산
    if(th < 11){
        char temp[10][10];
        for(int i = 0; i < 4; i++){ // 0 : 상, 1 : 우, 2 : 하, 3 : 좌
            memcpy(temp, board, sizeof(temp));
            int isEscape = tilt(temp, i);   // 선택된 방향으로 기울임
            if(isEscape == 1) ans = min(ans, th);   // 빨간 구슬만 탈출한 경우
            else if(isEscape == 0) c(temp, th + 1); // 아무 구슬도 탈출하지 못한 경우
        }
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;

    for(int i = 0; i < n; i++)
        for(int j = 0; j < m; j++)
            cin >> board[i][j];
    
    c(board, 1);
    cout << ((ans == INT_MAX) ? -1 : ans);
}

 

아래는 문제 풀이에 사용된 테스트 케이스입니다.

 

8 8
########
#......#
#..B...#
#......#
#.O..R.#
#......#
#......#
########

8 8
########
#......#
#......#
#......#
#.O.BR.#
#......#
#......#
########

8 8
########
#......#
#......#
#......#
#.OB#R.#
#......#
#......#
########

8 8
########
#......#
#......#
#......#
#.OR#B.#
#......#
#......#
########

8 8
########
#......#
#......#
#......#
#.O.#B.#
###....#
#R#....#
########

10 10
##########
#R#...##B#
#...#.##.#
#####.##.#
#......#.#
#.######.#
#...#.#..#
###.##...#
#O..#....#
##########

10 10
##########
#..R..##B#
#...#.##.#
#####.##.#
#......#.#
#.########
#...#....#
###.##.#.#
#.#....#O#
##########

 

'Algorithm > Simulation' 카테고리의 다른 글

[백준 14890번] 경사로 (C/C++)  (0) 2022.03.21
[백준 14502번] 연구소 (C/C++)  (0) 2022.03.20
[백준 14500번] 테트로미노 (C/C++)  (0) 2022.03.19
[백준 3190번] 뱀 (C/C++)  (0) 2022.03.19
[백준 14503번] 로봇 청소기 (C/C++)  (0) 2022.03.19
    'Algorithm/Simulation' 카테고리의 다른 글
    • [백준 14890번] 경사로 (C/C++)
    • [백준 14502번] 연구소 (C/C++)
    • [백준 14500번] 테트로미노 (C/C++)
    • [백준 3190번] 뱀 (C/C++)
    길민호(ethan.mino)
    길민호(ethan.mino)
    💻 호기심 많은 서버 개발자 길민호입니다.

    티스토리툴바