Post

코딩테스트 스터디-1339 단어 수학2

코딩테스트 스터디-1339 단어 수학2

ACMICPC 1339 단어 수학

1
2
3
4
5
6
7
백붕이는 수학학원에서 단어 수학 문제를 푸는 숙제를 받았다.

단어 수학 문제는 N개의 단어로 이루어져 있으며, 각 단어는 알파벳 대문자로만 이루어져 있다. 이때, 각 알파벳 대문자를 0부터 9까지의 숫자 중 하나로 바꿔서 N개의 수를 합하는 문제이다. 같은 알파벳은 같은 숫자로 바꿔야 하며, 두 개 이상의 알파벳이 같은 숫자로 바뀌어지면 안 된다.

예를 들어, GCF + ACDEB를 계산한다고 할 때, A = 9, B = 4, C = 8, D = 6, E = 5, F = 3, G = 7로 결정한다면, 두 수의 합은 99437이 되어서 최대가 될 것이다.

N개의 단어가 주어졌을 때, 그 수의 합을 최대로 만드는 프로그램을 작성하시오.

설명

문제를 보자마자 그리디 알고리듬을 떠올렸다. 그리디 알고리듬은 3년전 글 참고
그래서 그냥 가장 자리수 큰 수부터 9 붙이면 되지 않을까 했는데…

AAA
BBx15(BB가 15개)

수가 이렇게 있으면 AAA가 999고 BB가 88이면 8815 + 999 = 2319가 되어
AAA가 888이고 BB가 99인 99
15+888 = 2373보다 작게 된다.

그래서 처음에 생각한 것은 틀렸고…

발상의 전환을 해서 계산을 나중에 하면 되겠다.

  • 만약 주어진 수가 ABC, ABCDE 2개가 있다 할 때…
  • 이 두 수의 합을 풀어 쓰면 (Ax100+Bx10+C) + (Ax10000 + Bx1000 + Cx100 + Dx10 + E) 이렇게 할 수 있고..
  • 이를 다시 묶으면 Ax10100+Bx1010+Cx101+Dx10+Ex1 이렇게 정리할 수 있다.
  • 따라서 각 알파벳에 곱하는 수인 10101, 1010, 101, 10, 1을 따로 뺀 다음 가장 높은 순서대로 9,8,7,…을 부여하면 최대값이 나오지 않겠는가!

정답

아래는 파이썬으로 작성한 코드~

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
n = int(input())

dano = []

for i in range(n):
    dano.append(input())

jari = {}

# 각 알파벳이 몇 번씩 곱해지는지를 구하는 딕셔너리 만들어주기
# AAA+AAA 인 경우 A는 백/십/일의자리에 2번씩 등장하므로 222 이런식
for i in range(n):
    for j in range(len(dano[i])):
        if dano[i][j] in jari:
            jari[dano[i][j]] += 10 ** (len(dano[i])-j-1)
        else:
            jari[dano[i][j]] = 10 ** (len(dano[i])-j-1)

myotbon = []

for i in jari.values():
    myotbon.append(i)

# 위에서 구한 자리수를 리스트에 넣은 후 내림차순 정렬하고    
myotbon.sort(reverse = True)

answer = 0
sijak = 9

# 9부터 시작해서 제일 큰 것부터 곱해주고 더하면 끝!
for i in myotbon:
    answer += sijak * i
    sijak -= 1

print(answer)

후기

재밌는 문제라 올려보았다.
코딩테스트는 확실히 재치와 발상의 전환이 필요한 종목인 듯…머리가 10101이여야

This post is licensed under CC BY 4.0 by the author.