𝝅번째 알파카의 개발 낙서장

screen

[프로그래머스 / JAVA] Level 2 단체사진 찍기 (1835)

posts

알고리즘

시리즈 톺아보기

프로그래머스

프로그래머스
count

단체사진 찍기 🔗

랭크 사용 언어
Level 2 JAVA

🔗 단체사진 찍기

문제 설명 🔗

image

가을을 맞아 카카오프렌즈는 단체로 소풍을 떠났다. 즐거운 시간을 보내고 마지막에 단체사진을 찍기 위해 카메라 앞에 일렬로 나란히 섰다. 그런데 각자가 원하는 배치가 모두 달라 어떤 순서로 설지 정하는데 시간이 오래 걸렸다. 네오는 프로도와 나란히 서기를 원했고, 튜브가 뿜은 불을 맞은 적이 있던 라이언은 튜브에게서 적어도 세 칸 이상 떨어져서 서기를 원했다. 사진을 찍고 나서 돌아오는 길에, 무지는 모두가 원하는 조건을 만족하면서도 다르게 서는 방법이 있지 않았을까 생각해보게 되었다. 각 프렌즈가 원하는 조건을 입력으로 받았을 때 모든 조건을 만족할 수 있도록 서는 경우의 수를 계산하는 프로그램을 작성해보자.

입력 형식 🔗

입력은 조건의 개수를 나타내는 정수 nn개의 원소로 구성된 문자열 배열 data로 주어진다. data의 원소는 각 프렌즈가 원하는 조건이 N~F=0과 같은 형태의 문자열로 구성되어 있다. 제한조건은 아래와 같다.

  • 1 <= n <= 100
  • data의 원소는 다섯 글자로 구성된 문자열이다. 각 원소의 조건은 다음과 같다.
    • 첫 번째 글자와 세 번째 글자는 다음 8개 중 하나이다. { A, C, F, J, M, N, R, T } 각각 어피치, 콘, 프로도, 제이지, 무지, 네오, 라이언, 튜브를 의미한다. 첫 번째 글자는 조건을 제시한 프렌즈, 세 번째 글자는 상대방이다. 첫 번째 글자와 세 번째 글자는 항상 다르다.
    • 두 번째 글자는 항상 ~이다.
    • 네 번째 글자는 다음 3개 중 하나이다. { =, <, > } 각각 같음, 미만, 초과를 의미한다.
    • 다섯 번째 글자는 0 이상 6 이하의 정수의 문자형이며, 조건에 제시되는 간격을 의미한다. 이때 간격은 두 프렌즈 사이에 있는 다른 프렌즈의 수이다.

출력 형식 🔗

모든 조건을 만족하는 경우의 수를 리턴한다.

예제 입출력 🔗

n data answer
2 { "N~F=0", "R~T>2" } 3648
2 { "M~C<2", "C~M>1" } 0

예제에 대한 설명 🔗

첫 번째 예제는 문제에 설명된 바와 같이, 네오는 프로도와의 간격이 0이기를 원하고 라이언은 튜브와의 간격이 2보다 크기를 원하는 상황이다.

두 번째 예제는 무지가 콘과의 간격이 2보다 작기를 원하고, 반대로 콘은 무지와의 간격이 1보다 크기를 원하는 상황이다. 이는 동시에 만족할 수 없는 조건이므로 경우의 수는 0이다.

풀이 🔗

카카오 프렌즈들이 순서대로 서서 사진을 찍을 때, 각자 원하는 조건을 모두 충족하는 경우의 수를 구해야 한다.

이 경우, 배치가 중요하므로, 순열이 적합할 것이다.


순열 알고리즘을 구현하여 모든 경우의 수를 파악하고, 각 경우의 수마다 조건을 비교하여 해당되는 조건만 카운팅하면 될 것이다.

JAVA

0private void permutation(String[] output, boolean[] isVisit, int depth, int n, String[] data)
1{
2 // 마지막에 도달했을 경우
3 if (depth == NAMES.length)
4 {
5 answer += isValidate(n, data, output) ? 1 : 0;
6
7 return;
8 }
9
10 for (int i = 0; i < NAMES.length; i++)
11 {
12 // 방문하지 않았을 경우
13 if (!isVisit[i])
14 {
15 isVisit[i] = true;
16
17 output[depth] = NAMES[i];
18
19 permutation(output, isVisit, depth + 1, n, data);
20
21 isVisit[i] = false;
22 }
23 }
24}

구현한 순열 알고리즘은 위와 같다.

모든 경우의 수 계산이 끝나게 되면, isValidate 메서드로 조건이 일치하는지 여부를 파악한다.

제시된 조건에서 하나라도 일치하지 않을 경우 false를 반환하고, 모든 조건을 검사했음에도 문제가 없다면 true를 반환한다.

코드 🔗

JAVA

0/**
1 * 단체사진 찍기 클래스
2 *
3 * @author RWB
4 * @since 2021.12.26 Sun 20:35:07
5 */
6class Solution
7{
8 private static final String[] NAMES = { "A", "C", "F", "J", "M", "N", "R", "T" };
9 private int answer;
10
11 /**
12 * 해답 반환 메서드
13 *
14 * @param n: [int] 조건의 갯수
15 * @param data: [String[]] 조건
16 *
17 * @return [int] 해답
18 */
19 public int solution(int n, String[] data)
20 {
21 answer = 0;
22
23 int count = NAMES.length;
24
25 String[] output = new String[count];
26
27 boolean[] isVisit = new boolean[count];
28
29 permutation(output, isVisit, 0, n, data);
30
31 return answer;
32 }
33
34 /**
35 * 순열 메서드
36 *
37 * @param output: [String[]] 결과 저장 배열
38 * @param isVisit: [boolean[]] 방문 여부 배열
39 * @param depth: [int] 카운팅
40 * @param data: [String[]] 조건
41 * @param n: [int] 조건의 갯수
42 */
43 private void permutation(String[] output, boolean[] isVisit, int depth, int n, String[] data)
44 {
45 // 마지막에 도달했을 경우
46 if (depth == NAMES.length)
47 {
48 answer += isValidate(n, data, output) ? 1 : 0;
49
50 return;
51 }
52
53 for (int i = 0; i < NAMES.length; i++)
54 {
55 // 방문하지 않았을 경우
56 if (!isVisit[i])
57 {
58 isVisit[i] = true;
59
60 output[depth] = NAMES[i];
61
62 permutation(output, isVisit, depth + 1, n, data);
63
64 isVisit[i] = false;
65 }
66 }
67 }
68
69 /**
70 * 조건 검증결과 반환 메서드
71 *
72 * @param n: [int] 조건의 갯수
73 * @param data: [String[]] 조건
74 * @param output: [String[]] 결과 저장 배열
75 *
76 * @return [boolean] 조건 검증결과
77 */
78 private boolean isValidate(int n, String[] data, String[] output)
79 {
80 StringBuilder builder = new StringBuilder();
81
82 for (String out : output)
83 {
84 builder.append(out);
85 }
86
87 String text = builder.toString();
88
89 for (int i = 0; i < n; i++)
90 {
91 String[] temp = data[i].split("");
92
93 String name1 = temp[0];
94 String name2 = temp[2];
95 String operation = temp[3];
96
97 int distance = Integer.parseInt(temp[4]);
98
99 int realDistance = Math.abs(text.indexOf(name1) - text.indexOf(name2)) - 1;
100
101 // > 조건과 일치하지 않을 경우
102 if (operation.equals(">") && realDistance <= distance)
103 {
104 return false;
105 }
106
107 // = 조건과 일치하지 않을 경우
108 else if (operation.equals("=") && realDistance != distance)
109 {
110 return false;
111 }
112
113 // < 조건과 일치하지 않을 경우
114 else if (operation.equals("<") && realDistance >= distance)
115 {
116 return false;
117 }
118 }
119
120 return true;
121 }
122}