본문 바로가기

알고리즘

[SCPC] 12번: 방속의 거울

반응형

[SCPC] 12번: 방속의 거울

N 행 N 열로 이루어진 정사각형 격자구조 내에 방들 중에서 몇 개의 방에는 ╱ 또는 ╲ 형태의 대각선으로 45도 기울어진 양면거울이 들어 있다.

거울은 상하좌우에서 오는 빛을 다시 상하좌우 방향의 방으로 직각 반사시킨다. 본 문제에서는 '가장 윗줄에서 가장 왼쪽 방'의 왼쪽에서 레이저 포인터로 빛을 수평(0도)으로 비추었을 때 빛이 거치는 서로 다른 거울 개수를 계산하려고 한다.

예를 들어, 위 그림을 보자.

그림에서는 "①" 방으로 들어온 빛이 6번의 반사를 거친 후 3 ⅹ 3 크기의 격자구조 밖으로 빠져나간다. 그 중 "②" 방에 있는 거울의 경우, 한 거울의 양쪽 면에서 두 번의 반사가 일어난 것이다. 따라서 위의 예에서 빛을 반사한 거울은 5개이다. 이 문제를 해결하는 프로그램을 작성하시오.

메모리 사용 제한

  • heap, global, static (총계) : 256MB
  • stack : 1MB

입력

입력 파일에는 여러 개의 테스트 케이스가 포함되어 있다. 파일의 첫째 줄에는 테스트 케이스 개수를 나타내는 자연수 T 가 주어지고, 이후 차례로 T 개의 테스트 케이스가 주어진다. (1≤T≤20)

각각의 테스트 케이스 첫 번째 줄에는 정사각형 격자구조의 '한 변의 방 개수'를 나타내는 정수 N 이 주어진다. (1≤N≤1,000)

다음 줄부터는 N 개의 줄이 주어지고, 각 줄마다 N 개의 문자가 주어진다, 각 문자는 { ‘0’, ‘1’ , ‘2’ }에 속하는 문자 중 하나이다.

문자 ‘1’은 우측 상단에서 좌측 하단으로 45도 기울어진 양면거울이 그 방에 있다는 것을 나타내며,

문자 ‘2’는 좌측 상단에서 우측 하단으로 45도 기울어진 양면거울이 그 방에 있다는 것을 나타낸다.

그리고 문자 ‘0’은 거울이 없는 방임을 나타낸다. 각 줄에 들어 있는 문자들 사이에 빈칸(공백)은 없다.

출력

각 테스트 케이스의 답을 순서대로 표준출력으로 출력하여야 하며, 각 테스트 케이스마다 첫 줄에 “Case #T”를 출력하여야 한다. 이때 T는 테스트 케이스의 번호이다.

그 다음 줄에는 정사각형 격자구조 건물의 '맨 위 맨 왼쪽 방'의 왼쪽에서 수평(0도)으로 들어간 빛이 그 건물을 빠져나올 때까지 거치는 서로 다른 거울의 개수를 출력한다.

입출력예

입력

3
2
02
11
3
201
220
210
4
2121
0102
2101
2121

출력

Case #1
3
Case #2
5
Case #3
8

출처

[SCPC 2015 - 1차 예선]

등록자

이프로

풀이

방을 2차원 배열이라고 생각해봅시다. 레이저포인터는 (0, 0)에서 시작하여 거울을 만나지 않으면 오른쪽으로 한 칸 이동합니다. 따라서 초기 레이저포인터는 (1, 0)의 벡터라고 생각해도 될 것 같습니다.

거울은 레이저포인터를 반사시킵니다. 즉, 벡터의 방향을 바꿉니다. 거울의 종류와 벡터에 따른 변화는 다음과 같습니다.

벡터 '1' '2'
(1,0) (0,-1) (0,1)
(0,1) (-1,0) (1,0)
(-1,0) (0,1) (0,-1)
(0,-1) (1,0) (-1,0)

(x,y) 벡터가 '1' 거울을 만났을 때는 (-y,-x), '2' 거울을 만나면 (y,x)가 되는 것을 알 수 있습니다.

거울을 만날 때마다 벡터를 변환해주고, 현재 위치에 벡터를 더해줍니다. 현재 위치가 2차원 배열의 인덱스를 벗어났을 때 레이저가 방을 통과했다고 판단하여 루프를 종료합니다.

거울을 만나면 해당 거울이 처음 접촉하는 거울인지 판단하고, 처음 접촉하는 거울이면 횟수를 셉니다.

#include <vector>
#include <iostream>

using namespace std;

int Answer;

int main(int argc, char** argv) {
  int T; cin >> T;

  int size;
  string row;
  vector<int> count;
  vector<string> room;
  pair<int, int> direction;

  for(auto test_case = 0; test_case  < T; test_case++) {

    Answer = 0;
    direction = make_pair(1, 0);

    cin >> size;
    count = vector<int>(size * size, 0);
    room = vector<string>(size);
    for (auto i=0; i<size; i++) {
      cin >> room[i];
    }

    int x = 0, y = 0, tmp, sign;
    while (1) {
      if (room[y][x] != '0') {

        sign = 1;
        tmp = direction.first;

        if (room[y][x] == '1') {
          sign = -1;
        }

        direction.first = sign * direction.second;
        direction.second = sign * tmp;

        if (count[y * size + x] == 0) {
          count[y * size + x] = 1;
          Answer++;
        }
      }

      x += direction.first;
      y += direction.second;
      if (x < 0 || x >= size || y < 0 || y >= size) {
        break;
      }
    }

    cout << "Case #" << test_case+1 << endl;
    cout << Answer << endl;
  }

  return 0;
}
반응형

'알고리즘' 카테고리의 다른 글

[프로그래머스] 스킬트리  (0) 2020.08.22
[SCPC] 13번: 균일수  (0) 2020.08.14
[SCPC] 11번: 개구리 뛰기  (0) 2020.08.14
[백준] 10844번: 쉬운 계단 수  (0) 2020.08.14
[백준] 9461번: 파도반 수열  (0) 2020.08.13