Potato
μ•ˆλ…•ν•˜μ„Έμš”, κ°μž‘λ‹ˆλ‹€?πŸ₯” ^___^ 😺 github λ°”λ‘œκ°€κΈ° πŸ‘‰πŸ»

Algorithm/Baekjoon

[λ°±μ€€] (Swift μŠ€μœ„ν”„νŠΈ) 17103번 - κ³¨λ“œλ°”ν νŒŒν‹°μ…˜

감자 πŸ₯” 2022. 3. 1. 13:09
λ°˜μ‘ν˜•

 

문제 링크

https://www.acmicpc.net/problem/17103

 

17103번: κ³¨λ“œλ°”ν νŒŒν‹°μ…˜

첫째 쀄에 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 개수 T (1 ≤ T ≤ 100)κ°€ 주어진닀. 각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λŠ” ν•œ μ€„λ‘œ 이루어져 있고, μ •μˆ˜ N은 짝수이고, 2 < N ≤ 1,000,000을 λ§Œμ‘±ν•œλ‹€.

www.acmicpc.net

 

문제 ν•΄κ²° 아이디어

  1. ν•¨μˆ˜ isPrimeNumber
    • ν˜„μž¬ μž…λ ₯받은 μˆ˜κΉŒμ§€ 무슨 μ†Œμˆ˜κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ λ°°μ—΄λ‘œ 정리
    • 예λ₯Όλ“€μ–΄ 9κ°€ μž…λ ₯되면, [2, 3, 5, 7] 이 λ°˜ν™˜λœλ‹€.
  2. main
    • μž…λ ₯받은 num κΉŒμ§€ 무슨 μ†Œμˆ˜κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ isPrimeNums λ°°μ—΄ 생성
    • 2λΆ€ν„° num/2 κΉŒμ§€ 반볡
      • μ™œ num/2 냐? 10을 예둜 λ“€λ©΄, (3, 7), (5, 5) (7, 3) μ΄λ ‡κ²Œ κ³¨λ“œλ°”ν νŒŒν‹°μ…˜μ΄ 3쌍이 μ‘΄μž¬ν•˜κ²Œ λœλ‹€. ν•˜μ§€λ§Œ 문제 μ„€λͺ…ν•΄μ„œ μ΄λ ‡κ²Œ 된 경우, μˆœμ„œκ°€ λ’€λ°”λ€Œμ–΄λ„ ν•˜λ‚˜λ‘œ μ·¨κΈ‰ν•œλ‹€κ³  ν–ˆκΈ°μ—, 닡은 3쌍이 μ•„λ‹ˆλΌ 2쌍이 λœλ‹€. λ”°λΌμ„œ num/2 κΉŒμ§€ 루프λ₯Ό 돌게되면, 뒀에 λ°˜λ³΅λ˜λŠ” 것듀은 count ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— num/2 둜 λ²”μœ„λ₯Ό μ„€μ •ν–ˆλ‹€.
    • j와 num - j κ°€ λͺ¨λ‘ primeNums 배열에 μ‘΄μž¬ν•œλ‹€λ©΄, count+1

이 아이디어λ₯Ό κ·ΈλŒ€λ‘œ μ½”λ“œλ‘œ κ΅¬ν˜„ν–ˆλ‹€.

 

λ‚΄κ°€ ν‘Ό 풀이 - μ‹œκ°„μ΄ˆκ³Ό

*------------ μ‹œκ°„μ΄ˆκ³Ό ----------------*/
import Foundation

let n = Int(readLine()!)!

//μ†Œμˆ˜ 생성 ν•¨μˆ˜
func isPrimeNumber (n: Int) -> Array<Int> {
    var primeNums: [Int] = []
    var check = Array(repeating: true, count: n+1)
    check[0] = false
    check[1] = false

    for i in 0..<n+1 {
        if check[i] == true {
            var j = 2

            while (i*j) <= n {
                check[i*j] = false
                j += 1
            }
        }
    }

    for i in 0..<check.count {
        if check[i] == true {
            primeNums.append(i)
        }
    }
    return primeNums
}


///μž…λ ₯λ°›κΈ°
for i in 0..<n {
    let num = Int(readLine()!)! //μž…λ ₯받은 수
    var count = 0
    let primeNums = isPrimeNumber(n: num) //μž…λ ₯받은 numκΉŒμ§€ μ‘΄μž¬ν•˜λŠ” μ†Œμˆ˜

    for j in stride(from: 2, through: num/2, by: 1) {
        if primeNums.contains(j) { //num-jν•œ κ²°κ³Όκ°€ μ†Œμˆ˜λ©΄ count+1
            if primeNums.contains(num-j) {
                count+=1
            }
        }
    }

    print(count)
}

 

 

λ‚΄κ°€ ν‘Ό 풀이 - λ§žμ•˜μŠ΅λ‹ˆλ‹€!

비ꡐ적 μ™œ μ‹œκ°„μ΄ˆκ³ΌμΈμ§€ λΉ λ₯Έ μ‹œκ°„λ‚΄λ‘œ 찾을 수 μžˆμ—ˆλ‹€. κ°€μž₯ μ‹œκ°„μ„ λΉ λ₯΄κ²Œ 쀄일 수 μžˆλŠ” 반볡문 λ¨Όμ € μ‚΄νŽ΄λ³΄λ©΄μ„œ λ²”μœ„λ₯Ό μˆ˜μ •ν•΄μ£Όμ—ˆκ³ , 2차둜 또 μ‹œκ°„μ΄ˆκ³Όκ°€ 뜨길래 λ‘λ²ˆμ§Έλ‘œ μ†Œμˆ˜μƒμ„±ν•¨μˆ˜λ₯Ό Int둜 λ°”κΎΈλŠ” 과정을 μ€„μ—¬μ€ŒμœΌλ‘œμ¨ μ‹œκ°„μ΄ˆκ³Όλ₯Ό ν•΄κ²° ν•  수 μžˆμ—ˆλ‹€.

  • μ†Œμˆ˜ 생성 ν•¨μˆ˜
    • for λ¬Έ 돌 λ•Œ 0λΆ€ν„° n+1 돌게됨
    • μ΄λ ‡κ²Œ ν•˜κ²Œλ˜λ©΄ μ‹œκ°„λ³΅μž‘λ„ O(N)
    • λ²”μœ„ 2 ~ nμ—μ„œ n의 μ œκ³±κ·Όκ°’λ³΄λ‹€ μž‘μ€ 뢀뢄듀에 λŒ€ν•œ μ²˜λ¦¬κ°€ λλ‚˜λ©΄, μ œκ³±κ·Όκ°’λ³΄λ‹€ 큰 λΆ€λΆ„μ˜ κ°’ λ˜ν•œ μ²˜λ¦¬κ°€ λœλ‹€λŠ” 말
    • μ‹œκ°„λ³΅μž‘λ„λ₯Ό sqrt μ œκ³±κ·Όμ„ μ‚¬μš©ν•΄μ„œ 쀄여쀄 수 μžˆλ‹€.
  • μ†Œμˆ˜ μƒμ„±ν•¨μˆ˜ bool → Int
    • μ΄λ ‡κ²Œ ν•˜λŠ” κ³Όμ •μ—μ„œ μ‹œκ°„λ³΅μž‘λ„κ°€ 더 μΆ”κ°€λœλ‹€.
    • λ”°λΌμ„œ κ·Έλƒ₯ Bool ν˜•νƒœλ‘œ λ°˜ν™˜ν•΄μ£Όκ³ , indexλ₯Ό ν™œμš©ν•΄λ³΄μž.
import Foundation

let n = Int(readLine()!)!

//μ†Œμˆ˜ 생성 ν•¨μˆ˜
func isPrimeNumber (n: Int) -> Array<Bool> {
    var check = Array(repeating: true, count: n+1)
    check[0] = false
    check[1] = false

    for i in 0..<Int(sqrt(Double(n)))+1 {
        if check[i] == true {
            var j = 2

            while (i*j) <= n {
                check[i*j] = false
                j += 1
            }
        }
    }
    return check
}


//μž…λ ₯λ°›κΈ°
for i in 0..<n {
    let num = Int(readLine()!)! //μž…λ ₯받은 수
    var count = 0
    let primeNums = isPrimeNumber(n: num) //μž…λ ₯받은 numκΉŒμ§€ μ‘΄μž¬ν•˜λŠ” μ†Œμˆ˜

    for j in stride(from: 2, through: num/2, by: 1) {
        if primeNums[j] == true { //num-jν•œ κ²°κ³Όκ°€ μ†Œμˆ˜λ©΄ count+1
            if primeNums[num-j] == true {
                count+=1
            }
        }
    }

    print(count)
}

 

 

이 문제의 핡심은 μ†Œμˆ˜λ₯Ό ꡬ할 λ•Œ μ—λΌν† μŠ€ν…Œλ„€μŠ€μ˜ 체 λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμ΄μ—ˆλ‹€.

μ—λΌν† μŠ€ν…Œλ„€μŠ€ 체 λž€?

λŒ€λŸ‰μœΌλ‘œ λΉ λ₯΄κ²Œ μ†Œμˆ˜λ₯Ό κ΅¬ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€.

β–· μ—λΌν† μŠ€ν…Œλ„€μŠ€ 체 원리

μ—λΌν† μŠ€ν…Œλ„€μŠ€μ˜ μ²΄λŠ” κ°€μž₯ λ¨Όμ € μ†Œμˆ˜λ₯Ό νŒλ³„ν•  λ²”μœ„λ§ŒνΌ 배열을 ν• λ‹Ήν•˜μ—¬, ν•΄λ‹Ήν•˜λŠ” 값을 λ„£μ–΄μ£Όκ³ , 이후에 ν•˜λ‚˜μ”© μ§€μ›Œλ‚˜κ°€λŠ” 방법을 μ΄μš©ν•œλ‹€.

  1. 배열을 μƒμ„±ν•˜μ—¬ μ΄ˆκΈ°ν™”ν•œλ‹€. (μ›ν•˜λŠ” 숫자만큼 true 던, 0으둜던 배열을 μ΄ˆκΈ°ν™”)
  2. 2λΆ€ν„° μ‹œμž‘ν•΄μ„œ νŠΉμ • 수의 λ°°μˆ˜κ°€ λ˜λŠ” 수λ₯Ό λͺ¨λ‘ μ§€μš΄λ‹€. (μ§€μšΈ λ•Œ 자기 μžμ‹ μ€ μ§€μš°μ§€ μ•Šκ³  (μ†Œμˆ˜μ΄κΈ° λ•Œλ¬Έ) 이미 μ§€μ›Œμ§„ μˆ˜λŠ” κ±΄λ„ˆλ›΄λ‹€.)
  3. 2λΆ€ν„° μ‹œμž‘ν•˜μ—¬ λ‚¨μ•„μžˆλŠ” 수λ₯Ό λͺ¨λ‘ 좜λ ₯ν•œλ‹€.

 

μ—λΌν† μŠ€ν…Œλ„€μŠ€μ˜ 체λ₯Ό μ™œ λŒ€λŸ‰μœΌλ‘œ, λΉ λ₯΄κ²Œ κ΅¬ν• λ•Œ μ‚¬μš©ν• κΉŒ? κ·Έ μ΄μœ λŠ” μ—λΌν† μŠ€ν…Œλ„€μŠ€ 체 μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹œκ°„λ³΅μž‘λ„λŠ” 거의 μ„ ν˜•μ— κ°€κΉŒμš΄μš΄ ꡉμž₯히 λΉ λ₯Έ!! O(Nlog(logN)) μ‹œκ°„ λ³΅μž‘λ„λ₯Ό 가진닀. λ”°λΌμ„œ λΉ λ₯΄κ³ , μ •ν™•ν•˜κ²Œ, λŒ€λŸ‰μ˜ μ†Œμˆ˜λ₯Ό ꡬ할 λ•Œ μ‚¬μš©ν•  수 μžˆλŠ” 것이닀.

λ°˜μ‘ν˜•