Skip to content

Commit

Permalink
docs: BOJ 19942
Browse files Browse the repository at this point in the history
  • Loading branch information
Parkjju committed Jul 29, 2024
1 parent a84a41c commit 3d9eeb5
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 0 deletions.
Binary file added docs/.vuepress/assets/algorithm/bit-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ module.exports = {
'/algorithm/230112-swift',
'/algorithm/graph',
'/algorithm/backtrack',
'/algorithm/240729-bit',
],
},
{
Expand Down
79 changes: 79 additions & 0 deletions docs/algorithm/240729-bit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
title: 비트 마스킹
tags: ['Algorithm']
---

## 비트 연산 기초

`0100`이라는 4비트 데이터는 10진수 4를 나타낸다. 이를 `[false, true, false, false]` 불리언 배열로 나타낼 수 있다.

![bit-1](../.vuepress/assets/algorithm/bit-1.png)

:::tip << 연산자

주로 `<<` 비트마스킹 연산자를 코딩테스트에서 쓸 때는 `1 << 4` 이런식으로 사용한다. 왼쪽 피연산자 값을 1로 두고 계산할 때가 많다.

:::

- `^`, XOR 연산자는 같은 비트를 false로 반환해주는 연산자이다.
- `~`, NOT 연산자는 모든 비트를 반전시킨다. `~value = -(value + 1)`이다.

비트연산을 사용하는 이유는 특정 불리언 집합 배열을 하나의 수로 표현하여 수행시간을 단축할 수 있기 때문이다.

## 비트 연산 활용법

1. idx번째 비트끄기: `S &= ~(1 << idx)`
2. idx번째 비트 XOR 연산: `S ^= (1 << idx)`, 토글기능과 동일하다. idx번째 비트를 반전시킨다.
3. 최하위 켜져있는 비트 찾기: `idx = (S & -S)`, 오른쪽에서부터 탐색해서 처음 1인 비트를 찾는다.
4. 크기가 n인 집합의 모든 비트를 켜기: `(1 << n) - 1`
5. idx번째 비트를 켜기: `S |= (1 << idx)`
6. idx번째 비트가 켜져 있는지 확인하기: `if(S & (1 << idx))`

### 활용법 1. 모든 경우의 수 세기

`{사과, 딸기, 포도, 배}` 그룹에 대해 그룹을 지을 수 있는 모든 경우의 수는 16이다. 이들을 모두 출력해보자.

```swift
let input = ["사과", "딸기", "포도", ""]

for i in 0...1<<input.count {
var ret = ""
for j in 0..<input.count {
if i & (1<<j) != 0 {
ret += input[j] + " "
}
}
print(ret)
}
```

1. i를 0부터 16까지 순회한다.
2. 이진수 i에 대해서 `XXXX`의 j번째 비트가 켜져있는지 확인한다.
3. 켜져있으면 input 인덱싱을 하여 경우의 수 출력 리스트에 추가한다.

### 활용법 2. 매개변수

아래 코드는

```swift
let input = ["사과", "딸기", "포도", ""]

func go(_ num: Int) {
var ret = ""

for i in 0..<input.count {
if (num & (1<<i)) != 0 {
ret += input[i] + " "
}
}
print(ret)
}

for i in 1..<4 {
go(1 | (1 << i))
}
```

1. `go(1 | (1 << i))`를 통해 순회하며 각각 1,2,3번째 인덱스 비트를 켠다. 왼쪽 피연산자 숫자 1로 인해 "사과" 비트는 켜져있다.
2. 0, 1, 2, 3 비트가 켜져있는지 확인한다.
3. 사과 비트와 함께 켜져있는 다른 비트 위치 기준으로 input을 순회하여 문자열에 데이터를 추가한다.
1 change: 1 addition & 0 deletions docs/algorithm/baekjoon.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ title: PS 모음집
- [2589 보물섬](./ps/inflearn/swift/2589.md)
- [2529 부등호](./ps/inflearn/swift/2529.md)
- [2231 분해합](./ps/inflearn/swift/2231.md)
- [19942 다이어트 - 비트 마스킹](./ps/inflearn/swift/19942.md)

## PS 아카이빙 - C++

Expand Down
70 changes: 70 additions & 0 deletions docs/algorithm/ps/inflearn/swift/19942.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: BOJ 19942 - 다이어트
tags: ['Algorithm']
---

[문제 링크](https://www.acmicpc.net/problem/19942)

## 문제

1. 조합을 통해 완전탐색하는 문제
2. 사전 순이라는 정의에 따라 원소 갯수와 상관없이 `[3]`보다 `[1,2,3]`이 앞선다는 것을 명심해야됨
3. for문의 i 변수는 N개 중 선택된 i개를 의미한다.
4. for문의 j 변수를 통해 선택된 i의 이진데이터 1비트값을 기준으로 input을 인덱싱한다.

```swift
import Foundation

let N = Int(readLine()!)!
var input: [[Int]] = .init(repeating: .init(repeating: 0, count: 5), count: N)
var minimum: [Int] = readLine()!.split(separator: " ").map { Int($0)! }
var value = Int.max
var retValue: [Int:[[Int]]] = [:]

for i in 0..<N {
input[i] = readLine()!.split(separator: " ").map { Int($0)! }
}

for i in 1..<1<<N {
var nutrientSum = [0, 0, 0, 0]
var money = 0
var indicies: [Int] = []

// 고르기
for j in 0..<N {
if i & (1 << j) != 0 {
nutrientSum[0] += input[j][0]
nutrientSum[1] += input[j][1]
nutrientSum[2] += input[j][2]
nutrientSum [3] += input[j][3]
money += input[j][4]
indicies.append(j)
}
}

if nutrientSum[0] >= minimum[0]
&& nutrientSum[1] >= minimum[1]
&& nutrientSum[2] >= minimum[2]
&& nutrientSum[3] >= minimum[3] {
if value >= money {
value = money
if let _ = retValue[value] {
retValue[value]!.append(indicies)
} else {
retValue[value] = [indicies]
}
}
}
}
if value == Int.max {
print(-1)
exit(0)
}
print(value)
retValue[value]!.sorted(by: { prev, next in
return prev.map { String($0) }.joined() < next.map { String($0) }.joined()
})[0]
.forEach({
print($0 + 1, terminator: " ")
})
```

0 comments on commit 3d9eeb5

Please sign in to comment.