Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MuchanKim/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
| 차시 | 날짜 | 문제유형 | 링크 | 풀이 |
|:----:|:---------:|:----:|:-----:|:----:|
| 1차시 | 2025.03.29 | 구현 | [개미](https://www.acmicpc.net/problem/3048)|https://github.com/AlgoLeadMe/AlgoLeadMe-14/pull/3|
| 2차시 | 2025.04.11 | 에라토스테네스의채 | [소-난다!](https://www.acmicpc.net/problem/19699)|https://github.com/AlgoLeadMe/AlgoLeadMe-14/pull/10|

---
63 changes: 63 additions & 0 deletions MuchanKim/에라토스테네스의체/소난다.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Foundation

// 에라토스테네스의 체
func getPrimes(_ maxNum: Int) -> [Bool] {
var isPrime = Array(repeating: true, count: maxNum + 1)
isPrime[0] = false
isPrime[1] = false

for i in 2...Int(Double(maxNum).squareRoot()) {
if isPrime[i] {
for j in stride(from: i * i, through: maxNum, by: i) {
isPrime[j] = false
}
}
}

return isPrime
}
Comment on lines +4 to +18
Copy link
Collaborator

@bishoe01 bishoe01 Apr 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 어처피 소수 판단하겠구나해서 그냥 엄청 간단한 소수 판별 함수 짜주고 시작했어요!

그래서 무꺼보고, 아 이거 에라토스테네스하는게 훨씬 효율적이었나해서 좀 더 알아보니까

소수를 많이 판별해야 하거나 범위가 좁을 경우에는
에라토스테네스의 체를 사용하는 게 재활용도 가능하니까 훨씬 효율적이라네요 !

근데 저는 이 문제는 소가 최대 9마리밖에 안돼서 조합의 개수가 엄청 적고,
근데 9라는 작은 수에 비해서는 각 마리당 무게가 1000 이하라서 (이 수도 충분히 작을 수 있지만 소의 수에 비해서는 좀 큰느낌) 메모리 면에서 좀 비효율적일수도 있을것같다는 생각을 해봤습니다 !
사실 마리수나, 무게나 그렇게 큰 효율을 요구하는 문제는 아닌 것 같지만 혹시나 나중에 도움이 될까해서 말씀드려봐요!

그래서 이렇게 되게 적은 수 정도는 직접 판단해도 충분히 괜찮겠다는 생각이 들었어요!
짜는데도 훨씬 쉬우니까 시간 절약에 좀 도움이 될 수 있을까해서 공유드립니다 !

에라토스 테네스 채 : O(n log log n)
isPrime : O(√n) (대신 얘는 큰 수에 대해서 나눗셈 연산이 많이 들어감)

알아낸 것

  • 수가 적을수록 간단하게 만든 함수가 더 빠름
  • 수가 높아질수록 에라토스 압승 (대신에 수가 클지라도, 범위가 엄청 넓은데, 판단해야하는 개수는 적고 엄청 듬성 듬성 있다면 비효율적-메모리)
    사실 이렇게 효율따질 정도가 오면 무조건 체가 좋은 것 같아요
func isPrime(_ n: Int) -> Bool { // 소수 판단 함수
    guard n > 1 else { return false }
    if n == 2 {
        return true
    }
    for i in 2 ... Int(sqrt(Double(n)))+1 {
        if n % i == 0 {
            return false
        }
    }
    return true
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇네요! 소수 판별 문제에서는 그냥 에라토스테네스체가 정답이다라고 생각했는데 위 문제처럼 판별 할 수가 많지 않은 경우에는 불필요 할 수도 있겠네요.
핀은 에라토스테네스체를 염두하지 않고 바로 소수 판별로 들어간 걸까요? 아니면 구분 할 케이스가 별로 없다고 판단하고 간단하게 구현하신걸까요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 깊게 생각은하지않고, 그냥 소수판별하는구나!해서 일단 간단하게 구현해놓고 시작했어요!
제출하면서 시간초과뜨면 그때 체를 써야겠다 했습니다 !


func solution(_ n: Int, _ m: Int, _ cowsWeight: [Int]) -> String {
if m > n || n <= 0 || m <= 0 {
return "-1"
}

// 모든 무게 합의 최대값 계산
var maxPossibleSum = 0
for weight in cowsWeight {
maxPossibleSum += weight
}

let isPrime = getPrimes(maxPossibleSum)

var result: Set<Int> = []
// 비트마스크를 이용한 조합 생성
let totalCombinations = 1 << n

for mask in 0..<totalCombinations {
// 1의 개수 (선택된 원소 수) 확인
var count = 0
var sum = 0

for i in 0..<n {
if (mask & (1 << i)) != 0 {
count += 1
sum += cowsWeight[i]
}
}

// 정확히 m개가 선택되고, 그 합이 소수인 경우
if count == m && sum >= 2 && isPrime[sum] {
result.insert(sum)
}
}
Comment on lines +37 to +53
Copy link
Collaborator

@bishoe01 bishoe01 Apr 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비트마스킹 미쳤네요...
비트에서 선택된 인덱스로 하는건 알겠는데, 지피티쌤한테 계속 물어봐서 감 정도만 잡았습니다..
나중에 블로그 같은데에 정리하면서 한 번 제대로 다듬어봐야겠네요..!

아래는 짱피티쌤한테 하나하나 다 달라해서 한번 흐름따라가봤던 표입니다!
다른 PR하시는분들께 도움이 되길바라며..

1 << 4 = 16 → 총 16개의 부분집합(0부터 15까지 mask 순회)

mask (10진수) mask (2진수) 선택된 인덱스 선택된 값들 count sum
0 0000 [] [] 0 0
1 0001 [0] [2] 1 2
2 0010 [1] [4] 1 4
3 0011 [0, 1] [2, 4] 2 6
4 0100 [2] [5] 1 5
5 0101 [0, 2] [2, 5] 2 7
6 0110 [1, 2] [4, 5] 2 9
7 0111 [0, 1, 2] [2, 4, 5] 3 11
8 1000 [3] [7] 1 7
9 1001 [0, 3] [2, 7] 2 9
10 1010 [1, 3] [4, 7] 2 11
11 1011 [0, 1, 3] [2, 4, 7] 3 13
12 1100 [2, 3] [5, 7] 2 12
13 1101 [0, 2, 3] [2, 5, 7] 3 14
14 1110 [1, 2, 3] [4, 5, 7] 3 16
15 1111 [0, 1, 2, 3] [2, 4, 5, 7] 4 18

예를 들어 mask = 5 (0101)일 때

  • 인덱스 0번과 2번이 선택됨 → [2, 5]
  • sum = 7
  • count = 2
  • count == m이면 sum이 소수인지 검사

Copy link
Collaborator Author

@MuchanKim MuchanKim Apr 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이해가 어렵더라고요... 거의 피티 선생님이 풀어줬다고봐도 무방합니다. 그래서 다른분들 코드가 기다려지는 부분... 핀 열심히 하는 모습보니까 동기부여되고 좋네요! 항상 정성 피드백 굿쟙입니다. 리뷰 다 달고 이 문제는 꼭 다시 보려구요.,!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래도 얘기하지만 비트마스킹은 생각도 못했네요 ㄷㄷ
위에 표로 올려주신 핀도 감사합니다 이해가 쉽네요.

그런데 코드를 보다 보니, count 값이 이미 m과 같아졌다면 이후에도 계속 반복문을 돌면서 sum을 계산하는 것이 없어도 되지 않을까요?? (제가 잘못 이해했을 수도 있씁니다.ㅎㅎ)

지금은 아래코드처럼 루프를 무조건 0부터 n-1까지 끝까지 도는 구조인 것 같습니다!
결론적으로 count가 m을 초과해도 끝까지 다 도는 것 같습니다.

for i in 0..<n {
    if (mask & (1 << i)) != 0 {
        count += 1
        sum += cowsWeight[i]
    }
}

문제에서 원하는 건 정확히 m개의 소를 선택했을 때의 합이니깐
아래처럼 if count > m { break }로 반복을 미리 종료하면 성능 개선이 좀 더 될 것 같슴다!!

for i in 0..<n {
    if (mask & (1 << i)) != 0 {
        count += 1
        if count > m { break } 
        sum += cowsWeight[i]
    }
}

특히 N이 커지면 영향이 클 수 있을 것 같슴다...!
놓친게 있다면 알려주십셔,,,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 저도 비트마스킹으로 할 생각은 못했어요!! (사실 비트마스킹을 아직 잘 모르기도 하고)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

핀이 적어주신 비트마스킹이 이해 하는데 도움이 많이 됏네요 감사합니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

세션시간에 리뷰하는 개고수 장님..!


let sortedResult = Array(result).sorted()
return sortedResult.isEmpty ? "-1" : sortedResult.map { String($0) }.joined(separator: " ")
}

let input = readLine()!.split(separator: " ").map { Int($0)! }
let cowWeightArray = readLine()!.split(separator: " ").map { Int($0)! }

let res = solution(input[0], input[1], cowWeightArray)
Comment on lines +59 to +62
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

백준은 진짜 항상 입력받는게 번거롭네요.. 코드완성한다음에 MOO의 입력받는부분 야무지게 가져왔습니닷

  • 이전에 개미에서 배운 solution()묶어주는거 같이 쓰고 있어요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

약간 이 부분 보고 있으면 프로그래머스식의 문제로 바꿔서 푸는 느낌이 있는 것 같아요 ㅋㅋㅋㅋ..

print(res)