👆 링크
🤞 문제
👌 코드
🖖 풀이
🖐 Git gist 주소
https://programmers.co.kr/learn/courses/30/lessons/1835
카카오프렌즈 캐릭터가 단체사진을 찍기 위해 카메라 앞에 일렬로 나란히 서야 한다. 그런데 네오는 프로도와 나란히 서기를 원하고, 튜브가 뿜은 불을 맞은 적이 있던 라이언은 튜브에게서 적어도 세 칸 이상 떨어져서 서기를 원한다.
각 캐릭터가 원하는 조건을 입력으로 받았을 때 모든 조건을 만족할 수 있도록 서는 경우의 수를 계산하는 프로그램을 작성해보자.
package programmers_1835_takeAGroupPhoto;
import java.util.*;
/*
*
* 프로그래머스
* 1835. 단체사진 찍기
* https://programmers.co.kr/learn/courses/30/lessons/1835
* 2021-05-13
*
* */
class Solution {
static String[] condition;
static int answer = 0;
static boolean visited[];
static Map<Character, Integer> friends;
static Map<Integer, Integer> line;
public int solution(int n, String[] data) {
answer = 0;
visited = new boolean[8];
friends = new HashMap<>();
line = new HashMap<>();
condition = data;
friends.put('A', 0);
friends.put('C', 1);
friends.put('F', 2);
friends.put('J', 3);
friends.put('M', 4);
friends.put('N', 5);
friends.put('R', 6);
friends.put('T', 7);
dfs(0);
return answer;
}
private void dfs(int order) {
if(order == 8) {
if(checkLogic()) answer++;
return;
}
for(int identity = 0; identity < 8; identity++) {
if(!visited[identity]) {
line.put(identity, order);
visited[identity] = true;
dfs(order + 1);
visited[identity] = false;
}
}
}
//조건체크 메소드
private boolean checkLogic() {
//데이터 추출
for(String data : condition) {
int obj1 = friends.get(data.charAt(0));
int obj2 = friends.get(data.charAt(2));
int order1 = line.get(obj1); //obj1의 순서
int order2 = line.get(obj2); //obj2의 순서
char op = data.charAt(3);
int value = data.charAt(4)-'0' + 1;
if(op == '=') {
if(Math.abs(order1 - order2) != value) return false;
}else if(op == '<') { //미만
if(Math.abs(order1 - order2) >= value) return false;
}else { //초과
if(Math.abs(order1 - order2) <= value) return false;
}
}
return true;
}
}
line
이 조건에 맞는지 체크한다.모든 경우의 수가 8!
= 40,320
이기 때문에 완전 탐색으로 푸는 것이 가능하다.
Map
객체로 각 캐릭터에 매칭되는 Character
와 Integer
를 저장하고, 문자열을 읽으며 해당 Character
에 매핑되는 Integer
값으로 파싱한다.▼ friends
에 각 캐릭터의 문자형과 숫자형을 저장한다.
friends.put('A', 0);
friends.put('C', 1);
friends.put('F', 2);
friends.put('J', 3);
friends.put('M', 4);
friends.put('N', 5);
friends.put('R', 6);
friends.put('T', 7);
Map<Character, Integer> friends
Key | Value |
---|---|
A | 0 |
C | 1 |
F | 2 |
J | 3 |
M | 4 |
N | 5 |
R | 6 |
T | 7 |
Value
는 각 문자를 Integer
형으로 구분하기 위한 숫자이다.
❓ 굳이 숫자형으로 저장하는 이유
A
C
F
J
M
N
R
T
를 반복문으로 돌리기 위해서는 숫자형이어야 편하기 때문이다.
❓ 굳이Map
에 저장 안해도 되지 않나
맞다.char[] friends = {'A', 'C', 'F', 'J', 'M', 'N', 'R', 'T'};
배열로 풀어도 무관하다.
▼ 0~7
번째에 설 캐릭터를 정한다.
private void dfs(int order) {
if(order == 8) {
if(checkLogic()) answer++;
return;
}
for(int identity = 0; identity < 8; identity++) {
if(!visited[identity]) {
line.put(identity, order);
visited[identity] = true;
dfs(order + 1);
visited[identity] = false;
}
}
}
dfs(int order)
로 0부터 7까지 돌며, line
에 identity
와 order
를 저장한다.
order
: n번째 순서에
identity
: 어떤 캐릭터가 서있는지
💡 identity
= 7
, order
= 0
이라면 맨 0
번째에 T(7)
가 선다.
for
문으로 n번째 순서에 올 수 있는 캐릭터의 모든 경우의 수를 탐색한다.
중복방지를 위해 visited
로 체크해준다.
해당 재귀함수를 빠져나온 후엔 다시 visited
를 해제해준다.
order
=8
일 시, 8명 캐릭터 모두 일렬로 서있기 때문에 checkLogic()
함수로 주어진 조건에 맞는 상태인지 확인한다.
▼ data = (obj1)~(obj2)(op)(value)
for(String data : condition) {
int obj1 = friends.get(data.charAt(0));
int obj2 = friends.get(data.charAt(2));
int order1 = line.get(obj1); //obj1의 순서
int order2 = line.get(obj2); //obj2의 순서
char op = data.charAt(3);
int value = data.charAt(4)-'0' + 1;
...
data가 N~F=0
일 경우
data.charAt(0)
은 N , data.charAt(2)
는 F 이다.
friends
에서 Key가 N인 int
형 데이터를 찾아 obj1
에 넣는다.
💡 즉, obj1
과 obj2
는 카카오프렌즈를 int
타입으로 바꾼 변수이다.
▼ 조건을 만족하지 않으면 false
를 리턴하는 식으로 검사한다.
if(op == '=') {
if(Math.abs(order1 - order2) != value) return false;
}else if(op == '<') { //미만
if(Math.abs(order1 - order2) >= value) return false;
}else { //초과
if(Math.abs(order1 - order2) <= value) return false;
}
전역변수의 초기화를 solution
안에서 해주어야 정답처리가 된다.
이유는 잘 모르겠다 ㅠ
https://gist.github.com/ysyS2ysy/c91676d2fa524ff807081c7f4df1f4ae