11---
2- title : Bitmask
3- description : Bitmask에 대해 설명하는 페이지입니다.
2+ title : 비트마스크 ( Bitmask)
3+ description : 비트마스크 (Bitmask)에 대해 정리한 페이지입니다.
44date : 2024-03-25 00:00:00 +/-TTTT
55categories : [Algorithms]
66tags : [algorithm]
@@ -15,152 +15,238 @@ comments: true
1515<blockquote class =" prompt-info " ><p ><strong ><u >Tags</u ></strong > <br />
1616Algorithm</p ></blockquote >
1717
18- ## Introduction
19-
20- - ** Definition**
21- - ** 비트마스크(Bitmask)** 란 정수의 이진수 표현을 자료 구조로 쓰는 기법을 말한다.
22- - ** 비트(Bit)** : 이진수의 한 자리를 비트(Bit)라고 한다.
23- - ** 최상위 비트(Most Significant Bit)** : 2<sup >N - 1</sup >에 해당하는 비트를 말한다.
24- - ** 최하위 비트(Least Significant Bit)** : 2<sup >0</sup >에 해당하는 비트를 말한다.
25- - ** Advantages**
26- - ** 더 빠른 수행 시간** : 비트마스크 연산은 ** O(1)** 에 구현되는 것이 많으므로, 적절히 사용할 경우 다른 자료 구조를 사용하는 것보다 훨씬 빠르게 동작한다.
27- - ** 더 간결한 코드** : 다양한 집합 연산들을 반복문 없이 한 줄에 작성이 가능하다.
28- - ** 더 작은 메모리 사용량** : 비트마스크를 이용하는 코드들은 같은 데이터를 더 적은 메모리를 사용해 표현할 수 있다.
29- - ** 연관 배열을 배열로 대체** : Boolean 값 배열을 키로 갖는 연관 배열 객체 Map<Boolean[ ] , Integer>을 비트마스크를 이용하여 int[ ] 배열로 대체할 수 있다. 이를 통해 시간과 메모리를 절약할 수 있다.
30-
31- ## How to Use
32-
33- - ** 비트 연산자**
34- <table >
35- <tr >
36- <th>연산
37- <th>코드
38- <tr >
39- <td>AND 연산</td>
40- <td>a & b</td>
41- </tr >
42- <tr >
43- <td>OR 연산</td>
44- <td>a | b</td>
45- </tr >
46- <tr >
47- <td>XOR 연산</td>
48- <td>a ^ b</td>
49- </tr >
50- <tr >
51- <td>NOT 연산</td>
52- <td>~a</td>
53- </tr >
54- <tr >
55- <td>Left Shift 연산</td>
56- <td>a << b</td>
57- </tr >
58- <tr >
59- <td>Right Shift 연산</td>
60- <td>a >> b</td>
61- </tr >
62- - ** 비트마스크를 이용한 집합 구현**
63- - ** 꽉 찬 집합**
64- ``` java
65- int fullSet = (1 << 20 ) - 1 ;
66- ```
67- - ** 공집합**
68- ```java
69- int emptySet = 0 ;
70- ```
71- - ** 원소 추가**
72- ```java
73- bitSet |= (1 << p);
74- ```
75- - ** 원소의 포함 여부 확인**
76- ```java
77- // & 연산의 결과 값이 0 또는 (1 << p) 라는 점을 주의하자.
78- if (bitSet & (1 << p)) {
79- System . out. println(" 원소가 포함되어 있음." );
18+ ## 개요
19+
20+ ` 비트마스크(Bitmask) ` 에 대해 정리한 페이지입니다.
21+
22+ ## 비트마스크 (Bitmask)
23+
24+ ### 개념
25+
26+ ` 비트마스크(Bitmask) ` 란 정수의 이진수 표현을 자료 구조로 사용하는 기법을 말합니다.
27+
28+ <blockquote class =" prompt-info " ><p ><strong ><u >Info.</u ></strong ><br />
29+ <b >비트(Bit)</b >: 이진수의 한 자리를 비트(Bit)라고 합니다.<br />
30+ <b >최상위 비트(Most Significant Bit)</b >: 2<sup >N - 1</sup >에 해당하는 비트를 말합니다.<br />
31+ <b >최하위 비트(Least Significant Bit)</b >: 2<sup >0</sup >에 해당하는 비트를 말합니다.</p ></blockquote >
32+
33+ ### 특징
34+
35+ 비트마스크의 특징은 다음과 같습니다.
36+
37+ - ` 간결한 코드 `
38+
39+ 다양한 집합 연산들을 반복문 없이 한 줄에 작성할 수 있습니다.
40+
41+ - ` 더 작은 메모리 사용량 `
42+
43+ 비트마스크를 이용하는 코드들은 같은 데이터를 더 적은 메모리를 사용해 표현할 수 있습니다. 특히 Boolean 값 배열을 키로 갖는 연관 배열 객체 ` Map<Boolean[], Integer> ` 을 비트마스크를 이용하여 ` int[] ` 배열로 대체할 수 있어서 시간과 메모리를 절약할 수 있습니다.
44+
45+ - ` 시간 복잡도(Time Complexity) `
46+
47+ 대부분의 비트마스크 연산은 ` O(1) ` 의 시간 복잡도를 갖으므로 적절히 사용할 경우 다른 자료 구조를 사용하는 것보다 훨씬 빠르게 동작합니다.
48+
49+ ### 비트 연산자
50+
51+ | 연산 | 코드 |
52+ | ---------------- | ------ |
53+ | AND 연산 | a & b |
54+ | OR 연산 | a \| b |
55+ | XOR 연산 | a ^ b |
56+ | NOT 연산 | ~ a |
57+ | Left Shift 연산 | a << b |
58+ | Right Shift 연산 | a >> b |
59+
60+ ### 비트마스크를 이용한 집합 구현
61+
62+ #### 꽉 찬 집합
63+
64+ ``` java
65+ int fullSet = (1 << 20 ) - 1 ;
66+ ```
67+
68+ #### 공집합
69+
70+ ``` java
71+ int emptySet = 0 ;
72+ ```
73+
74+ #### 원소 추가
75+
76+ ``` java
77+ bitSet |= (1 << p);
78+ ```
79+
80+ #### 원소의 포함 여부 확인
81+
82+ ``` java
83+ // & 연산의 결과 값이 0 또는 (1 << p) 라는 점을 주의해야 합니다.
84+ if (bitSet & (1 << p)) {
85+ System . out. println(" 원소가 포함되어 있음." );
86+ }
87+ ```
88+
89+ #### 원소의 삭제
90+
91+ ``` java
92+ bitSet &= ~ (1 << p);
93+ ```
94+
95+ #### 원소의 토글
96+
97+ ``` java
98+ bitSet ^ = (1 << p);
99+ ```
100+
101+ #### 두 집합에 대한 연산
102+
103+ ``` java
104+ int added = (a | b); // a와 b의 합집합
105+ int intersection = (a & b); // a와 b의 교집합
106+ int removed = (a & ~ b); // a에서 b를 뺀 차집합
107+ int toggled = (a ^ b); // a와 b중 하나에만 포함된 원소들의 집합
108+ ```
109+
110+ #### 집합의 크기
111+
112+ ``` java
113+ int bitCount(int x) {
114+ if (x == 0 ) return 0 ;
115+ return x % 2 + bitCount(x / 2 );
116+ }
117+ ```
118+
119+ | 컴파일러 또는 언어 | 집합의 크기 |
120+ | ------------------ | ---------------------------- |
121+ | gcc/g++ | \_\_ builtin_popcount(bitSet) |
122+ | Visual C++ | \_\_ popcnt(bitSet) |
123+ | Java | Integer.bitCount(bitSet) |
124+
125+ #### 최소 원소 지우기
126+
127+ ``` java
128+ bitSet &= (bitSet - 1 );
129+ ```
130+
131+ #### 2의 거듭제곱 값인지 여부 확인
132+
133+ ``` java
134+ // 2의 거듭제곱 값들의 이진수 표현에는 켜진 비트가 하나 밖에 없습니다.
135+ if ((num & (num - 1 )) == 0 ) {
136+ System . out. println(" 2의 거듭제곱 값입니다." );
137+ }
138+ ```
139+
140+ #### 모든 부분 집합 순회
141+
142+ ``` java
143+ for (int subset = bitSet; subset > 0 ; subset = ((subset - 1 ) & bitSet)) {
144+ // subset은 bitSet의 부분 집합
145+ // (subset > 0): 공집합은 방문하지 않습니다.
146+ }
147+ ```
148+
149+ ## Example
150+
151+ - <a href =" https://github.com/HyunJinNo/Algorithm/blob/main/Number%20Theory/Sieve%20of%20Eratosthenes/Sieve_of_Eratosthenes.js " target =" _blank " >비트마스크를 사용하는 에라토스테네스의 체</a >
152+
153+ ``` javascript
154+ // 비트마스크(Bitmask)를 사용하는 에라토스테네스의 체의 구현
155+
156+ const n = 1000000 ; // n개의 원소
157+
158+ /**
159+ * Uint8Array와 비트마스크를 사용하여 메모리 사용량을 8분의 1로 줄인다.
160+ * 0: 합성수, 1: 소수
161+ */
162+ const sieve = new Uint8Array (Math .floor ((n + 7 ) / 8 )).fill (255 );
163+
164+ /**
165+ * 비트를 0으로 바꿔서 x가 소수가 아니라고 표시한다.
166+ * @param {number} x
167+ */
168+ const setComposite = (x ) => {
169+ sieve[x >> 3 ] &= ~ (1 << (x & 7 ));
170+ };
171+
172+ /**
173+ * x가 소수인지 확인한다
174+ * @param {number} x 판정할 값
175+ * @returns {Boolean} 소수 여부
176+ */
177+ const isPrime = (x ) => {
178+ if (sieve[x >> 3 ] & (1 << (x & 7 ))) {
179+ return true ;
180+ } else {
181+ return false ;
80182 }
81- ```
82- - ** 원소의 삭제**
83- ```java
84- bitSet &= ~ (1 << p);
85- ```
86- - ** 원소의 토글**
87- ```java
88- bitSet ^ = (1 << p);
89- ```
90- - ** 두 집합에 대한 연산**
91- ```java
92- int added = (a | b); // a와 b의 합집합
93- int intersection = (a & b); // a와 b의 교집합
94- int removed = (a & ~ b); // a에서 b를 뺀 차집합
95- int toggled = (a ^ b); // a와 b중 하나에만 포함된 원소들의 집합
96- ```
97- - ** 집합의 크기**
98- ```java
99- int bitCount(int x) {
100- if (x == 0 ) return 0 ;
101- return x % 2 + bitCount(x / 2 );
183+ };
184+
185+ setComposite (0 );
186+ setComposite (1 );
187+ for (let x = 2 ; x <= n; x++ ) {
188+ if (isPrime (x)) {
189+ for (let y = x * x; y <= n; y += x) {
190+ setComposite (y);
191+ }
102192 }
103- ```
104- < table>
105- < tr>
106- < th> 컴파일러 혹은 언어< / th>
107- < th> 집합의 크기< / th>
108- < / tr>
109- < tr>
110- < td> gcc/ g++ < / td>
111- < td> __builtin_popcount(bitSet)< / td>
112- < / tr>
113- < tr>
114- < td> Visual C ++ < / td>
115- < td> __popcnt(bitSet)< / td>
116- < / tr>
117- < tr>
118- < td> Java</ td>
119- < td> Integer . bitCount(bitSet)< / td>
120- < / tr>
121- < / table>
122- - ** 최소 원소 찾기**
123- ```java
124- int firstElement = (bitSet & - bitSet);
125- ```
126- < table>
127- < tr>
128- < th> 컴파일러 혹은 언어< / th>
129- < th> 최소 원소< / th>
130- < / tr>
131- < tr>
132- < td> gcc/ g++ < / td>
133- < td> __builtin_ctz(bitSet)< / td>
134- < / tr>
135- < tr>
136- < td> Visual C ++ < / td>
137- < td> __BitScanForward(bitSet)< / td>
138- < / tr>
139- < tr>
140- < td> Java</ td>
141- < td> Integer . numberOfTrailingZeros(bitSet)< / td>
142- < / tr>
143- < / table>
144- - ** 최소 원소 지우기**
145- ```java
146- bitSet &= (bitSet - 1 );
147- ```
148- - ** 2 의 거듭제곱 값인지 여부 확인**
149- ```java
150- // 2의 거듭제곱 값들의 이진수 표현에는 켜진 비트가 하나 밖에 없음.
151- if ((num & (num - 1 )) == 0 ) {
152- System . out. println(" 2의 거듭제곱 값입니다." );
193+ }
194+
195+ for (let x = 2 ; x <= n; x++ ) {
196+ if (isPrime (x)) {
197+ console .log (x);
153198 }
154- ```
155- - ** 모든 부분 집합 순회**
156- ```java
157- for (int subset = bitSet; subset > 0 ; subset = ((subset - 1 ) & bitSet)) {
158- // subset은 bitSet의 부분 집합
159- // (subset > 0): 공집합은 방문하지 않는다.
199+ }
200+ ```
201+
202+ - <a href =" https://www.acmicpc.net/problem/1311 " target =" _blank " >1311번: 할 일 정하기 1</a >
203+
204+ ``` javascript
205+ const path =
206+ process .platform === " linux" ? " /dev/stdin" : " ./JavaScript/input.txt" ;
207+ const input = require (" fs" ).readFileSync (path).toString ().split (" \n " );
208+
209+ const n = Number (input[0 ]); // 사람과 일의 수, 1 <= n <= 20
210+ const cache = Array .from (Array (n), () => new Array (1 << n).fill (- 1 ));
211+ const arr = [];
212+
213+ for (let i = 1 ; i <= n; i++ ) {
214+ arr .push (input[i].split (" " ).map (Number ));
215+ }
216+
217+ /**
218+ * 모든 일을 하는데 필요한 비용의 최솟값을 구하는 함수
219+ * @param {number} index (index)번째 사람
220+ * @param {number} visited 지금까지 한 일
221+ * @returns 최소 비용 값
222+ */
223+ const solve = (index , visited ) => {
224+ if (index >= n) {
225+ return 0 ;
226+ } else if (cache[index][visited] !== - 1 ) {
227+ return cache[index][visited];
160228 }
161- ```
162229
163- ## Examples
230+ let result = Number . MAX_SAFE_INTEGER ;
164231
165- - < a href= " https://github.com/HyunJinNo/Algorithm/blob/main/Number%20Theory/Sieve%20of%20Eratosthenes/Sieve_of_Eratosthenes.js" target= " _blank" > 비트마스크를 사용하는 에라토스테네스의 체< / a>
166- - < a href= " https://github.com/HyunJinNo/Algorithm/blob/main/Bitmask/GRADUATION.js" target= " _blank" > GRADUATION . js< / a>
232+ for (let i = 0 ; i < n; i++ ) {
233+ if ((~ visited & (1 << i)) === 1 << i) {
234+ visited |= 1 << i;
235+ result = Math .min (
236+ result,
237+ arr[index][n - 1 - i] + solve (index + 1 , visited)
238+ );
239+ visited &= ~ (1 << i);
240+ }
241+ }
242+
243+ cache[index][visited] = result;
244+ return result;
245+ };
246+
247+ console .log (solve (0 , 0 ));
248+ ```
249+
250+ ## 참고 자료
251+
252+ - <a href =" https://www.yes24.com/product/goods/8006522 " target =" _blank " >알고리즘 문제 해결 전략 세트 | 구종만 | 인사이트(insight) - 예스24</a >
0 commit comments