https://www.acmicpc.net/problem/16508
16508번: 전공책
곧 졸업을 앞둔 민호는 대학교 생활 동안 구매만 해놓고 한 번도 펴보지 않은 전공책에 먼지가 쌓여 있는 것을 보고는, 이 책들을 어떻게 처리해야 할지 고민 중이다. 열심히 고민한 끝에 민호는
www.acmicpc.net
브루트포스 문제.
백트랙킹으로 풀었는데 정말 많이 틀렸다..^^
지금 생각해 보면 사실 그렇게 틀릴 일이 없는데,, 백트래킹 문제를 꽤 오랫동안 안 풀었더니 더 헤맸던 것 같다
다시 공부하자!
처음에는 만들고자 하는 단어와 전공책 제목과 직접적으로 비교하고, removeLast(), remove() 메소드를 사용해서 삭제해 주는 쪽으로 했다. 그런데 이렇게 하니 시간초과 발생(91%에서..😭).
c++에서는 이런 문제를 alphabet 배열을 만들어서 진행하기도 했기 때문에 이번에도 그런 식으로 접근해봤다.
func searchWord(count: Int, sum: Int) {
if n == count {
if checkWord() { //만약 선택한 책에서 단어를 만들어낼 수 있다면
answer = min(answer, sum)
}
return
}
let tmp = books[count].0.map{String($0)}
for i in 0..<tmp.count {
let index = Int(UnicodeScalar(tmp[i])!.value) - Int(UnicodeScalar("A").value)
bookAlpha[index] += 1
}
searchWord(count: count + 1, sum: sum + books[count].1)
for i in 0..<tmp.count {
let index = Int(UnicodeScalar(tmp[i])!.value) - Int(UnicodeScalar("A").value)
bookAlpha[index] -= 1
}
searchWord(count: count + 1, sum: sum)
}
searchWord(count: 0, sum: 0)
처음에는 선택할 전공책 1권~n권을 따로 정했었는데, 시간초과가 계속 발생해서 다른 분의 코드를 살펴봤다... ^.ㅠ
위 코드를 보면 알 수 있듯이
-----------------------------------------
선택한 전공책의 제목 알파벳 개수 카운팅
재귀호출(현재 전공책을 선택한 경우)
위에서 선택했던 전공책 제목 알파벳 개수 차감
재귀호출(현재 전공책을 선택하지 않은 경우)
-----------------------------------------
이런 형태를 가진다. 직접 해보면 알겠지만 이렇게 하면 전공책을 선택하는 모든 경우의 수가 나온다.
func checkWord() -> Bool {
for i in 0..<26 {
if talpha[i] > bookAlpha[i] { return false }
}
return true
}
checkWord 메소드에서 만들고자 하는 단어를 만들 수 있는지 체크한다.
searchWord 메소드에서 bookAlpha 배열에 선택한 전공책 제목 알파벳 개수를 카운팅을 해놨는데
각 알파벳을 체크하는데, 만약 만들고자 하는 단어의 알파벳 개수가 더 많으면 return false
선택한 전공책 제목으로는 만들고자 하는 단어를 만들 수 없다는 의미다.
[전체 코드]
import Foundation
/*
가장 적은 비용으로 민호가 원하는 단어를 만들기 위해 어떤 전공책을 선택해야 할까?
단어를 만들기 위해 선택해야 하는 전공책의 가장 적은 가격의 합 구하기
*/
//input
let t = readLine()!.map{ String($0) }
let n = Int(readLine()!)!
var books = [(String, Int)]()
var talpha = [Int](repeating: 0, count: 26)
var bookAlpha = [Int](repeating: 0, count: 26)
var answer = Int.max
for i in 0..<t.count {
let index = Int(UnicodeScalar(t[i])!.value) - Int(UnicodeScalar("A").value)
talpha[index] += 1
}
for _ in 0..<n {
let input = readLine()!.split(separator: " ").map{ String($0) }
books.append((input[1], Int(input[0])!))
}
//list에 있는 책들로 단어를 만들 수 있는지 체크하는 함수
func checkWord() -> Bool {
for i in 0..<26 {
if talpha[i] > bookAlpha[i] { return false }
}
return true
}
func searchWord(count: Int, sum: Int) {
if n == count { //정한 책의 개수를 채웠을 경우
if checkWord() { //만약 선택한 책에서 단어를 만들어낼 수 있다면
answer = min(answer, sum)
}
return
}
let tmp = books[count].0.map{String($0)}
for i in 0..<tmp.count {
let index = Int(UnicodeScalar(tmp[i])!.value) - Int(UnicodeScalar("A").value)
bookAlpha[index] += 1
}
searchWord(count: count + 1, sum: sum + books[count].1)
for i in 0..<tmp.count {
let index = Int(UnicodeScalar(tmp[i])!.value) - Int(UnicodeScalar("A").value)
bookAlpha[index] -= 1
}
searchWord(count: count + 1, sum: sum)
}
searchWord(count: 0, sum: 0)
if answer == Int.max { answer = -1 }
print(answer)
새로운 백트랙킹 방법을 알게된 것 같다.
다른 문제에도 사용해봐야지!
고군분투한 흔적... 너무 힘들었다..^^
'알고리즘 > 백준' 카테고리의 다른 글
[백준/Swift] 1764번: 듣보잡 (0) | 2023.01.26 |
---|---|
[백준/Swift] 14889번: 스타트와 링크 (1) | 2023.01.26 |
[백준/Swift] 14501번 퇴사(백트래킹) (0) | 2023.01.19 |
[백준/Swift] 1436번: 영화감독 숌 (0) | 2023.01.17 |
[백준/Swift] 9012번: 괄호 (0) | 2023.01.17 |