넘치게 채우기

[BOJ] 4042 : Vampires! 본문

PS/BOJ

[BOJ] 4042 : Vampires!

riveroverflow 2024. 10. 8. 11:35
728x90
반응형

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

BOJ - Vampires!

문제 유형: 구현

문제 난이도: Silver I

 

 

문제

The big media gimmick these days seems to be vampires. Vampire movies, vampire television shows, vampire books, vampire dolls, vampire cereal, vampire lipstick, vampire bunnies – kids and teenagers and even some adults spend lots of time and money on vampire-related stuff. Surprisingly, nowadays vampires are often the good guys. Obviously, the ACM Programming Contest had better have a vampire problem in order to be considered culturally relevant.

As eveyone knows, vampires are allergic to garlic, sunlight, crosses, wooden stakes, and the Internal Revenue Service. But curiously they spend a good part of their time smashing mirrors. Why? Well, mirrors can’t hurt vampires physically, but it’s embarrassing to be unable to cast a reflection. Mirrors hurt vampire’s feelings. This problem is about trying to help them avoid mirrors.

In a room full of vampires and ordinary mortals there are a number of mirrors. Each mirror has one of four orientations – north, south, east, or west (the orientation indicates which side of the mirror reflects). A vampire is in danger of embarrassment if he or she is in a direct horizontal or vertical line with the reflecting side of a mirror, unless there are intervening objects (mortals or other mirrors). For example, in the following room layout

vampire V2 is exposed to a south-facing mirror and both vampires V1 and V2 are exposed to a west-facing mirror (note that a vampire can’t protect another vampire from embarrassment since neither one casts a reflection.) Your job is to notify each vampire of the directions in which there is danger of experiencing ENR (embarrassing non-reflectivity).

 

(서론은 생략)

뱀파이어는 거울로부터 쬐면 위험하다. 각 뱀파이어가 어느 방향으로부터 위험한지 구하시오.

단, 중간에 무언가가 있으면 거울을 막아줘서 괜찮다.(단, 뱀파이어 제외)

 

입력

각 테스트케이스틑 v o m으로 주어집니다.

각각 뱀파이어의 수, 일반인의 수, 거울의 수입니다.

각 v개의 라인은 각 뱀파이어의 x, y좌표의 쌍이 순서대로 주어집니다.

그 뒤 o개의 라인은 각 일반인들의 x, y좌표쌍이 주어집니다.

그 뒤 m개의 라인으로, (방향, 시작x좌표, 시작 y좌표, 종료 x좌표, 종료 y좌표)의 꼴로 거울 정보가 주어집니다.

방향은 N, S, E, W로, 한 줄로 나오는것이 보장됩니다. 이 방향은 거울이 보고 있는 방향을 뜻합니다.

 

칸이 중복되지 않는 것이 보장됩니다.

 

v o m이 0 0 0으로 주어질 시, 종료하시오.

 

출력

각 테스트케이스당, 위험에 처한 뱀파이어가 어디 방향으로부터 위험한지 출력하시오.

출력 순서는 

vampire <뱀파이어번호> <east, north, south, west>순서로 위험한 방향을 출력해야 합니다.

아무도 없는 경우, none을 반환합니다.

 

(자세한 사항은 문제 홈페이지의 예제 참고)

 

풀이

해시맵을 이용할 것이다.

row[y]에는 그 y좌표에 있는 개체들을 저장한다.

{x좌표, 개체번호}로 저장한다.

개체 번호는 다음과 같이 정의했다:

0: 뱀파이어

1: 일반 사람

2: 서쪽을 보는 거울

3: 남쪽을 보는 거울

4: 북쪽을 보는 거울

5: 동쪽을 보는 거울

 

col[x]에도 ={y좌표, 개체번호}로 저장한다.

모든 뱀파이어와 사람, 거울에 대해서 저장해주면 된다.

거울은 범위에 해당하는 모든 칸을 하나하나 추가해준다.

 

각 뱀파이어에 대해서, 동-북-남-서의 방향을 점검할 것이다.

1)동쪽방향 위협 체크: 

현재 같은 y좌표에서 자신보다 x좌표가 더 큰 서쪽을 바라보는 거울을 찾는다.

  만약 있다면, 뱀파이어의 x좌표 < 중간 방해물의 x좌표 < 거울의 x좌표를 만족하는 중간 요소가 있는지 찾는다.

  이 중간 요소는 서쪽을 바라보는 거울이면 안되고, 또, 뱀파이어면 안된다.

    만약 중간 방해물이 있다면, 안전하다.
  만약 현재 같은 y좌표에서 만족하는 중간 방해물을 찾지 못했다면, 동쪽으로부터 위협이 있는 것이다. 더 이상의 탐색을 멈춘다.

 

2)북쪽방향 위협 체크:

현재 같은 x좌표에서 자신보다 y좌표가 더 큰 남쪽을 바라보는 거울을 찾는다.

  만약 있다면, 뱀파이어의 y좌표 < 중간 방해물의 y좌표 < 거울의 y좌표를 만족하는 중간 요소가 있는지 찾는다.

  이 중간 요소는 남쪽을 바라보는 거울이면 안되고, 또, 뱀파이어면 안된다.

    만약 중간 방해물이 있다면, 안전하다.
  만약 현재 같은 x좌표에서 만족하는 중간 방해물을 찾지 못했다면, 북쪽으로부터 위협이 있는 것이다. 더 이상의 탐색을 멈춘다.

 

3)남쪽방향 위협 체크:

 2번의 반대로 하면 된다.

 

4)서쪽방향 위협 체크:

1번의 반대대로 하면 된다.

 

하나 이상이라도 위협이 있다면, 그 뱀파이어에 대해 위협 정보를 출력한다.

 

만약 모든 뱀파이어가 안전하다면, none을 반환한다.

 

코드

C++

#include <bits/stdc++.h>

using namespace std;

// 0: vampire
// 1: ordinary
// 2: west mirror
// 3: south mirror
// 4: north mirror
// 5: east mirror

void solve(int c, int v, int o, int m) {
  vector<pair<int, int>> vampires;
  unordered_map<int, vector<pair<int, int>>> row;
  unordered_map<int, vector<pair<int, int>>> col;

  char dir;
  int x0, y0, x1, y1;
  for (int i = 0; i < v; ++i) {
    cin >> x0 >> y0;
    vampires.push_back({x0, y0});
    row[y0].push_back({x0, 0});
    col[x0].push_back({y0, 0});
  }

  for (int i = 0; i < o; ++i) {
    cin >> x0 >> y0;
    row[y0].push_back({x0, 1});
    col[x0].push_back({y0, 1});
  }

  for (int i = 0; i < m; ++i) {
    int dircode;
    cin >> dir >> x0 >> y0 >> x1 >> y1;
    switch (dir) {
    case 'W':
      dircode = 2;
      break;
    case 'S':
      dircode = 3;
      break;
    case 'N':
      dircode = 4;
      break;
    case 'E':
      dircode = 5;
    }

    if (dircode == 3 || dircode == 4) {
      int from = min(x0, x1);
      int to = max(x0, x1);
      int y = y0;

      for (int j = from; j <= to; ++j) {
        col[j].push_back({y, dircode});
        row[y].push_back({j, dircode});
      }
    } else {
      int from = min(y0, y1);
      int to = max(y0, y1);
      int x = x0;

      for (int j = from; j <= to; ++j) {
        col[x].push_back({j, dircode});
        row[j].push_back({x, dircode});
      }
    }
  }

  bool flag = true;
  cout << "Case " << c << ":\n";
  for (int i = 0; i < v; ++i) {
    string status = "";
    int x = vampires[i].first;
    int y = vampires[i].second;

    // check east.
    for (const auto &element : row[y]) {
      if (element.second == 2 && element.first > x) {
        bool safe = false;
        for (const auto &shield : row[y]) {
          if (shield.second != 2 && shield.second != 0 && shield.first > x &&
              shield.first < element.first) {
            safe = true;
            break;
          }
        }
        if (!safe) {
          status += " east";
          break;
        }
      }
    }

    // check north
    for (const auto &element : col[x]) {
      if (element.second == 3 && element.first > y) {
        bool safe = false;
        for (const auto &shield : col[x]) {
          if (shield.second != 3 && shield.second != 0 && shield.first > y &&
              shield.first < element.first) {
            safe = true;
            break;
          }
        }
        if (!safe) {
          status += " north";
          break;
        }
      }
    }

    // check south
    for (const auto &element : col[x]) {
      if (element.second == 4 && element.first < y) {
        bool safe = false;
        for (const auto &shield : col[x]) {
          if (shield.second != 4 && shield.second != 0 && shield.first < y &&
              shield.first > element.first) {
            safe = true;
            break;
          }
        }
        if (!safe) {
          status += " south";
          break;
        }
      }
    }

    // check west.
    for (const auto &element : row[y]) {
      if (element.second == 5 && element.first < x) {
        bool safe = false;
        for (const auto &shield : row[y]) {
          if (shield.second != 5 && shield.second != 0 && shield.first < x &&
              shield.first > element.first) {
            safe = true;
            break;
          }
        }
        if (!safe) {
          status += " west";
          break;
        }
      }
    }

    if (status.size() != 0) {
      cout << "vampire " << i + 1 << status << "\n";
      flag = false;
    }
  }
  if (flag) {
    cout << "none\n";
  }
}

int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);

  int c = 1;
  int v, o, m;
  while (true) {
    cin >> v >> o >> m;
    if (v == 0 && o == 0 && m == 0) {
      break;
    }
    solve(c, v, o, m);
    c++;
  }
  return 0;
}
728x90
반응형

'PS > BOJ' 카테고리의 다른 글

[BOJ] 6907: Floor Plan  (0) 2024.10.09
[BOJ] 30892: 상어 키우기  (0) 2024.10.08
[BOJ] 2403: 게시판 구멍 가리기  (0) 2024.10.07
[BOJ] 6514: Expressions  (0) 2024.10.05
[BOJ] 자바의 형변환  (0) 2024.10.03