[Programmers/C] 거리두기 확인하기

Gyeongmin·2022년 1월 15일
0

문제풀이

목록 보기
2/4

개념

맨해튼 거리란?

두 테이블 T1, T2가 행렬 (r1, c1), (r2, c2)에 각각 위치하고 있다면, T1, T2 사이의 맨해튼 거리는 |r1 - r2| + |c1 - c2| 입니다.
간단하게 말하면 각 좌표의 차를 모두 더한 것입니다.

위키에 잘 설명되어 있습니다.
https://ko.wikipedia.org/wiki/%EB%A7%A8%ED%95%B4%ED%8A%BC_%EA%B1%B0%EB%A6%AC

문제 설명

개발자를 희망하는 죠르디가 카카오에 면접을 보러 왔습니다.

코로나 바이러스 감염 예방을 위해 응시자들은 거리를 둬서 대기를 해야하는데 개발 직군 면접인 만큼
아래와 같은 규칙으로 대기실에 거리를 두고 앉도록 안내하고 있습니다.

  • 대기실은 5개이며, 각 대기실은 5x5 크기입니다.
  • 거리두기를 위하여 응시자들 끼리는 맨해튼 거리가 2 이하로 앉지 말아 주세요.
  • 단 응시자가 앉아있는 자리 사이가 파티션으로 막혀 있을 경우에는 허용합니다.

예를 들어,

5개의 대기실을 본 죠르디는 각 대기실에서 응시자들이 거리두기를 잘 기키고 있는지 알고 싶어졌습니다. 자리에 앉아있는 응시자들의 정보와 대기실 구조를 대기실별로 담은 2차원 문자열 배열 places가 매개변수로 주어집니다. 각 대기실별로 거리두기를 지키고 있으면 1을, 한 명이라도 지키지 않고 있으면 0을 배열에 담아 return 하도록 solution 함수를 완성해 주세요.

제한사항

  • places의 행 길이(대기실 개수) = 5
    • places의 각 행은 하나의 대기실 구조를 나타냅니다.
  • places의 열 길이(대기실 세로 길이) = 5
  • places의 원소는 P,O,X로 이루어진 문자열입니다.
    • places 원소의 길이(대기실 가로 길이) = 5
    • P는 응시자가 앉아있는 자리를 의미합니다.
    • O는 빈 테이블을 의미합니다.
    • X는 파티션을 의미합니다.
  • 입력으로 주어지는 5개 대기실의 크기는 모두 5x5 입니다.
  • return 값 형식
    • 1차원 정수 배열에 5개의 원소를 담아서 return 합니다.
    • places에 담겨 있는 5개 대기실의 순서대로, 거리두기 준수 여부를 차례대로 배열에 담습니다.
    • 각 대기실 별로 모든 응시자가 거리두기를 지키고 있으면 1을, 한 명이라도 지키지 않고 있으면 0을 담습니다.

입출력 예

placesresult
[["POOOP", "OXXOX", "OPXPX", "OOXOX", "POXXP"], ["POOPX", "OXPXP", "PXXXO", "OXXXO", "OOOPP"], ["PXOPX", "OXOXP", "OXPOX", "OXXOP", "PXPOX"], ["OOOXX", "XOOOX", "OOOXX", "OXOOX", "OOOOO"], ["PXPXP", "XPXPX", "PXPXP", "XPXPX", "PXPXP"]][1, 0, 1, 1, 1]

입출력 예 설명

첫 번째 대기실

No.01234
0POOOP
1OXXOX
2OPXPX
3OOXOX
4POXXP
  • 모든 응시자가 거리두기를 지키고 있습니다.

두 번째 대기실

No.01234
0POOPX
1OXPXP
2PXXXO
3OXXXO
4OOOPP
  • (0, 0) 자리의 응시자와 (2, 0) 자리의 응시자가 거리두기를 지키고 있지 않습니다.
  • (1, 2) 자리의 응시자와 (0, 3) 자리의 응시자가 거리두기를 지키고 있지 않습니다.
  • (4, 3) 자리의 응시자와 (4, 4) 자리의 응시자가 거리두기를 지키고 있지 않습니다.

세 번째 대기실

No.01234
0PXOPX
1OXOXP
2OXPOX
3OXXOP
4PXPOX
  • 모든 응시자가 거리두기를 지키고 있습니다.

네 번째 대기실

No.01234
0OOOXX
1XOOOX
2OOOXX
3OXOOX
4OOOOO
  • 대기실에 응시자가 없으므로 거리두기를 지키고 있습니다.

다섯 번째 대기실

No.01234
0PXPXP
1XPXPX
2PXPXP
3XPXPX
4PXPXP
  • 모든 응시자가 거리두기를 지키고 있습니다.

두 번째 대기실을 제외한 모든 대기실에서 거리두기가 지켜지고 있으므로, 배열 [1, 0, 1, 1, 1]을 return 합니다.

코드

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

int* solution(const char*** places, size_t places_rows, size_t places_cols) {
    int* answer = (int*)malloc(sizeof(int) * 5);
    int person_r[5][25] = { 0 };
    int person_c[5][25] = { 0 };
    int count[5] = { 0 };
    
    // answer를 1로 초기화
    for(int k = 0; k < 5; k++)
        answer[k] = 1;
    
    // P의 위치를 저장
    for(int k = 0; k < 5; k++)
        for(int i= 0; i < places_rows; i++)
            for(int j = 0; j < places_cols; j++)
                if (places[k][i][j] == 'P'){
                    person_r[k][count[k]] = i;
                    person_c[k][count[k]] = j;
                    count[k]++;
                }                
    
    // 거리두기 계산
    for(int k = 0; k < 5; k++)
        for(int i = 0; i < count[k]; i++)
            for(int j = i + 1; j < count[k]; j++){
                // 맨해튼 거리가 1인 경우
                if (abs(person_r[k][i] - person_r[k][j]) == 1 && person_c[k][i] == person_c[k][j]){
                answer[k] = 0;
                break;
                }
                else if (abs(person_c[k][i] - person_c[k][j]) == 1 && person_r[k][i] == person_r[k][j]){
                answer[k] = 0;
                break;
                }
                // 맨해튼 거리가 2인 경우 (일직선)
                if (abs(person_r[k][i] - person_r[k][j]) == 2 && person_c[k][i] == person_c[k][j])
                    if (places[k][(person_r[k][i] + person_r[k][j]) / 2][person_c[k][i]] == 'O'){
                        answer[k] = 0;
                        break;
                    }
                if (abs(person_c[k][i] - person_c[k][j]) == 2 && person_r[k][i] == person_r[k][j])
                    if (places[k][(person_c[k][i] + person_c[k][j]) / 2][person_r[k][i]] == 'O'){
                        answer[k] = 0;
                        break;
                    }
                // 맨해튼 거리가 2인 경우 (대각선)
                if (abs(person_r[k][i] - person_r[k][j]) == 1 && abs(person_c[k][i] - person_c[k][j]) == 1)
                    if (places[k][person_r[k][i]][person_c[k][j]] == 'O' || places[k][person_r[k][j]][person_c[k][i]] == 'O'){
                        answer[k] = 0;
                        break;
                    }
            }

    return answer;
}

해석

경우의 수를 나누어서 풀었습니다.
문제에서 배열을 한꺼번에 주기 때문에 코드가 조금 복잡해 보입니다.

우선 answer 배열을 1로 초기화 시킨 후, 배열을 돌며 P가 있는지 검사합니다.
P를 발견하면 person_r에 행의 번호값을, person_c에 열의 번호값을 저장합니다.
P의 개수는 count에 저장됩니다.
반복문을 돌며 거리두기가 지켜지지 않은 경우, answer값을 0으로 변경합니다.

거리두기가 지켜지지 않은 경우는 다음과 같습니다.

  • 맨해튼 거리가 1인 경우
  • 맨해튼 거리가 2인 경우
    • 일직선에 위치해 있고, 중간에 O가 있는 경우
    • 대각선에 위치해 있고, 중간에 O가 있는 경우

문제링크 : https://programmers.co.kr/learn/courses/30/lessons/81302

profile
HSU 21 이경민

0개의 댓글