[백준] 1301번 - 비즈 공예 (Gold 3)
업데이트:
문제 링크
문제 설명
구슬의 가짓수 N과 각 종류의 구슬의 개수가 주어진다.
이 구슬들로 직선의 목걸이를 만들려고 하는데, 연속된 세개의 구슬은 모두 다른 색이어야 한다.
목걸이를 만들 수 있는 경우의 수를 구하시오.
정답 코드 및 설명
종류별로 사용된 구슬의 수와 마지막 구슬 두개가 정해져 있을 때 경우의 수가 몇 가지 가능한지를 구하면 된다.
N이 5 이하이므로 7차원 배열을 사용하면 쉽게 해결할 수 있다.
아래의 코드는 7차원 배열 대신 Map을 사용하여 top-down 방식으로 구현한 것이다.
Map의 키로는 종류별로 사용된 구슬의 수 및 마지막 구슬 두개가 저장된 객체가 들어간다.
이렇게 구현할 경우 구슬의 가짓수 N에 무관하게 문제를 풀 수 있다는 장점이 있다.
단점은 배열보다는 조금 더 느리다는 것이다. 해시를 계산하는 과정이 들어가기 때문이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
public class BOJ1301 {
int n, sum;
int[] color;
HashMap<Count, Long> count = new HashMap<>();
void input() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(br.readLine());
color = new int[n];
sum = 0;
for (int i = 0; i < n; i++) {
color[i] = Integer.parseInt(br.readLine());
sum += color[i];
}
}
class Count {
int[] countColor;
int secondToLast, last;
Count(int[] countColor, int secondToLast, int last) {
this.countColor = new int[n];
this.countColor = countColor.clone();
this.secondToLast = secondToLast;
this.last = last;
}
public boolean equals(Object o) {
if (!(o instanceof Count))
return false;
Count count = (Count) o;
if (secondToLast != count.secondToLast) return false;
if (last != count.last) return false;
for (int i = 0; i < n; i++)
if (countColor[i] != count.countColor[i]) return false;
return true;
}
public int hashCode() {
return Objects.hash(Arrays.hashCode(countColor), secondToLast, last);
}
}
long DP(Count curr) { // top-down 방식의 DP
if (count.get(curr) != null)
return count.get(curr);
int[] beforeCountColor = curr.countColor.clone();
beforeCountColor[curr.last]--;
long ans = 0;
for (int k = 0; k < n; k++) { // 마지막에서 세번째 구슬이 k인 경우
// 마지막에서 세번째 색이 k가 될 수 없는 경우(중복인 경우 또는 구슬 k를 다 쓴 경우)
if (k == curr.last || k == curr.secondToLast || beforeCountColor[k] == 0) continue;
Count before = new Count(beforeCountColor, k, curr.secondToLast);
ans += DP(before);
}
count.put(curr, ans);
return ans;
}
void initializeDP() {
int[] countColor = new int[n];
for (int i = 0; i < n; i++) {
countColor[i]++;
for (int j = 0; j < n; j++) {
countColor[j]++;
Count curr = new Count(countColor, i, j);
if (i != j) count.put(curr, 1L);
countColor[j]--;
}
countColor[i]--;
}
}
void solution() throws IOException {
input();
initializeDP();
long ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j == i) continue;
Count curr = new Count(color, j, i);
ans += DP(curr);
}
}
System.out.println(ans);
}
public static void main(String[] args) throws IOException {
new BOJ1301().solution();
}
}
댓글남기기