완전탐색을 하기 위해서는 여러 방법이 있을 수 있겠지만
만약 int arr[] = { 1, 2, 3, 4 }; 라는 배열이 있다고 할 때,
이 부분 집합들을 구해야 한다면 어떻게 해야 될까요??
부분집합 크기가 1인 경우, 2인 경우 .. 4인경우 다 나눠서 구할 수는 있지만
만약 arr의 크기가 100이라면? 그보다 크다면?!!
딱히 생각나지 않습니다.. 이때! bit 연산으로 쉽게 구할 수 있습니다!
0000
0001
0010 ...
이런식으로 각 결과마다 1인 부분만 출력한다면 쉽게 부분집합을 구할수 있겠죠??
먼저 코드를 보여드리고 설명하도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <iostream>
using namespace std;
int main() {
// 배열 크기
int n = 5;
// 11111을 10진수로 환산 했을 때의 값만큼 반복
// (이 경우 0 ~ 31)
for (int i = 0; i < (1 << n); i++) {
// 자리수만큼(이 경우 5) 반복하며
// 1인 자리는 1을, 아니면 0을 출력
for (int j = 0; j < n; j++) {
if (i & (1 << j))
cout << 1 << ' ';
else
cout << 0 << ' ';
}
cout << endl;
}
system("pause");
return 0;
}
|
cs |
먼저, 첫 번째 for문을 보면, (1 << n) 부분이 있습니다. 1을 n번만큼 왼쪽으로 옮긴다는 소리로,
1은 00001이니, 이를 5번 옮기면 100000가 되겠죠? 10진수로 보면 32!
즉, 2^5입니다. 그냥 pow(2, n) 으로 해도 상관 없겠지만 bit에 익숙해지는게 낫겠죠??
다음은 각 자리수 별로 체크하는 부분입니다.
여기에서 &는 둘다 1이어야 1을 반환하는 연산자입니다.
i가 5일 경우를 보면 ( 00101 ),
j == 0일때, (1 << 0)은 1이 한칸도 안움직였으니 그대로 1입니다.
00101 & 00001 = 00001 = 1 => true
그래서 1을 출력하겠죠?
j == 1일때, (1 << 1)
00101 & 00010 = 00000 = 0 => false
j == 2 일때, (1 << 2)
00101 & 00100 = 00100 = 4 => true
이후에는 다 0이므로 false 입니다.
이렇듯 안에 있는 두번째 for문은 1이 있다면 true 아니면 false로 처리하여 부분집합을 구하는 것입니다.
적절한 완전탐색 문제가 있다면 활용하면 좋겠네요!
질문이나 지적사항은 댓글로 부탁드립니다 :)
'알고리즘' 카테고리의 다른 글
문자열 탐색 알고리즘 KMP (0) | 2019.07.25 |
---|