[백준] 1339번 단어 수학 Java 풀이
PROBLEM
https://www.acmicpc.net/problem/1339
SOLUTION
문제 지문에서 단어의 개수, 수의 길이를 고려했을 때 브루트포스 알고리즘으로 접근해도 괜찮을 것 같다는 생각을 했다. 따라서, 각 알파벳 별로 숫자를 부여하는 모든 경우의 수를 정하고 최대값을 찾는다.
각 알파벳은 0~9 사이 숫자에 대응되므로 0~9까지의 순열을 구해서 각 경우의 수일 때 값을 계산한다.
시간 제한은 2초이지만 java라서 시간을 더 준건지, 2792ms로 아슬아슬하게 통과한 듯 싶다.
SOURCE CODE (JAVA)
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
import java.io.*;
import java.util.*;
public class Main {
static int N;
static int[] alphabetCount;
static String[] words;
static long max;
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine()); // 단어의 개수
int count = 0; // 순열의 크기를 결정하기 위해 등장한 알바펫의 종류를 센다.
alphabetCount = new int[26]; // 등장했던 알파벳들에 대해서 번호를 부여하기 위해 개수를 센다.
words = new String[N]; // 주어지는 단어들
for (int i=0; i<N; i++) {
words[i] = br.readLine();
for (int j=0; j<words[i].length(); j++) {
int alpha = words[i].charAt(j) - 'A';
if (alphabetCount[alpha] == 0) count++; // 0이면 첫 등장 이므로, 알파벳 종류 개수 + 1
alphabetCount[alpha]++;
}
}
perm(0, new boolean[26], new int[count]);
System.out.println(max);
br.close();
}
static void perm(int cnt, boolean[] visited, int[] res) {
if (cnt == res.length) { // 순열 완성
int[] charToNum = new int[26]; // 알파벳에 숫자를 부여한 것을 저장할 배열
int idx = 0;
for (int i=0; i<26; i++)
if (alphabetCount[i] != 0) // 등장했던 알파벳에 대해서
charToNum[i] = res[idx++]; // 순열 순서대로 숫자를 부여
// 등장한 알파벳에 숫자를 부여한 후에
// 주어진 문자열 words를 정수로 변환하여 result에 누적한다.
long result = 0L;
for (String word : words) {
long wtl = wordToLong(word, charToNum);
result += wtl;
}
if (result > max) // max값 업데이트
max = result;
return;
}
// Permutation
for (int i=0; i<10; i++) {
if (visited[i])
continue;
visited[i] = true;
res[cnt] = i;
perm(cnt+1, visited, res);
visited[i] = false;
}
}
// 문자열 word를 charToNum 배열을 통해서 각 글자를 정수로 변환
static long wordToLong(String word, int[] charToNum) {
StringBuilder resultSb = new StringBuilder();
for (char c : word.toCharArray())
resultSb.append(charToNum[c-'A']);
return Long.parseLong(resultSb.toString());
}
}
OFF THE RECORD
문제는 해결했지만 시간을 단축시키는 다른 방법을 좀 더 고민하던 중, 탐욕법으로 해결할 만한 실마리를 찾았다. 길이가 긴 단어의 앞글자에게 큰 숫자를 부여하자라는 방법이었는데, 테스트 케이스는 다 통과했지만 반례가 있었다.
1
2
3
4
3
ABCDE
CBAAZ
ZZZZZ
위와 같이 입력이 주어지면 ZZZZZ
를 큰 수로 만들기 위해서 ‘Z’가 9를 가져야하는 것을 직관적으로 알 수 있다.
하지만, 생각했던 방식에 따르면 길이가 같지만 먼저 등장한 ABCDE
의 첫 글자 ‘A’가 9를 가지게 되므로 예외가 생긴다. 따라서, 각 알파벳이 등장한 자리수를 고려해야하는 것을 알았지만, 해결하는 방법은 찾지 못해 다른 사람의 풀이를 참조했다.
수학적으로 접근하여 각 알파벳이 등장한 자리수를 표현할 수 있었다. 위 예시를 그대로 사용하자면 ABCDE
는 아래와 같은 것이다.
A | $ 10^4 = 10000 $ |
---|---|
B | $ 10^3 = 1000 $ |
C | $ 10^2 = 100 $ |
D | $ 10^1 = 10 $ |
E | $ 10^0 = 1$ |
CBAAZ
까지 적용하면 아래와 같다.
A | $ 10^4 + 10^2 + 10^1 = 10110 $ |
---|---|
B | $ 10^3 + 10^3 = 2000 $ |
C | $ 10^4 + 10^2 = 10100 $ |
D | $ 10^1 = 10 $ |
E | $ 10^0 = 1 $ |
Z | $ 10^0 = 1 $ |
ZZZZZ
까지 적용하면 아래와 같다.
A | $ 10^4 + 10^2 + 10^1 = 10110 $ |
---|---|
B | $ 10^3 + 10^3 = 2000 $ |
C | $ 10^4 + 10^2 = 10100 $ |
D | $ 10^1 = 10 $ |
E | $ 10^0 = 1 $ |
Z | $ 10^4 + 10^3 + 10^2 + 10^1 + 10^0 + 10^0 = 11112 $ |
즉 ‘Z’가 높은 숫자를 가져야 하는 것을 위와 같이 수치로 확인할 수 있고, 위 값에 따라 정렬한 후에 숫자를 부여하면 최대값을 구할 수 있다.
댓글 남기기