★ 비트(bit)
비트는 이진수(binary digit)로, 컴퓨터에서 사용되는 데이터의 최소 단위이다.
0/ 1 두 개의 값만을 가질 수 있으며, 이 두가지로 숫자를 표현하는 방법을 이진법이라고 한다.
★ 비트 마스트(BitMask)
비트연산을 사용해서 부분 집합을 표현할 수 있다.
비트마스크는 알고리즘 아닌 bit를 사용한 테크닉이다.
비트의 형태, 정수의 이진수 표현을 활용한 기법이다.
★ 다음과 같은 집합의 부분집합을 표현할 때,
{0, 1, 2, 3, 4}
[방법1] 다음과 같이 존재하는 인덱스로 표현할 수 있고
{0, 1, 2, 3, 4} = 1 1 1 1 1
{0, 2} = 0 0 1 0 1
{2, 3, 4} = 1 1 1 0 0
{2, 4} = 1 0 1 0 0
{1} = 0 0 0 1 0
각 요소는 인덱스처럼 표현할 수 있다.
즉, 집합 I번째 요소가 부분집합에 존재한다면 1을 의미하고 그렇지 않으면 0을 의미한다.
[방법2] 2진수를 10진수로 표현할 수도 있다.
{0, 1, 2, 3, 4} = 1 1 1 1 1 = 31
{0, 2} = 0 0 1 0 1 = 5
{2 ,3 4} = 1 1 1 0 0 = 28
{2, 4} = 1 0 1 0 0 = 20
★ 비트 연산
A | B | ~A | A & B | A | B | A ^ B |
0 | 0 | 1 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 1 | 1 | 0 |
★ shift 연산자
10<<2 : 10을 왼쪽으로 2비트 이동
<<n : n비트씩 왼쪽으로 이동, 왼쪽으로 밀려나간 비트가 사라지고, 오른쪽 빈자리에는 0이 채워진다. 결과는 10 * 2n을 곱한 것과 같다. |
10 << 2 : 10을 오른쪽으로 1비트 이동
>>n : 오른쪽으로 밀려나간 비트가 사라지고, 왼쪽 빈자리에는 부호 비트가 채워진다. (양수는 0으로 채워지고, 음수는 1로 채워진다. 만약, 이동 연산자의 부호 없는(unsigned) 정수형이면, 0으로 채워진다.) 결과는 10 / 2n 으로 나눈 것과 같다. |
(a + b) / 2 -> (a+b) >>1로 사용할수 있다. 비트 연산을 통해 추가, 검사, 제거, 토글을 할 수 있다 |
{ 2, 4, 5, 7 } = 1 0 1 1 0 1 0 0 = 180
0이 포함되어 있는지 검사 180 & 20 = 180 & (1<<0) = 0 1이 포함되어 있는지 검사 180 & 21 = 180 & (1<<1) = 0 2가 포함되어 있는지 검사 180 & 22 = 180 & (1<<2) = 4 3가 포함되어 있는지 검사 180 & 23 = 180 & (1<<3) = 0 4가 포함되어 있는지 검사 180 & 24 = 180 & (1<<4) = 16 |
1을 제거하기 180 & ~21 = 180 & ~(1<<1) = 180 2을 제거하기 180 & ~22 = 180 & ~(1<<2) = 176 3을 제거하기 180 & ~23 = 180 & ~(1<<3) = 180 4을 제거하기 180 & ~24 = 180 & ~(1<<4) = 164 |
1 추가하기 180 | 21 = 180 | (1<<1) = 182 2 추가하기 180 | 22 = 180 | (1<<2) = 180 3 추가하기 180 | 23 = 180 | (1<<3) = 188 4 추가하기 180 | 24 = 180 | (1<<4) = 180 |
1을 토글하기 180 ^ 21 = 180 ^ (1<<1) = 182 2을 토글하기 180 ^ 22 = 180 ^ (1<<2) = 176 3을 토글하기 180 ^ 23 = 180 ^ (1<<3) = 188 4을 토글하기 180 ^ 24 = 180 ^ (1<<4) = 164 |
현재 집합이 S일 때 i를 추가 s | (1 << i) i를 검사 s & ( 1 << i) i를 제거 s & ~(1 << i) i를 토글(1을0으로, 0을 1로) s ^ ( 1 << i ) 전체 집합 (1 << N) -1 공집합 0 |
[ 비트마스크 예제1]
#include <cstdio>
int main()
{
unsigned int data = 0x5678; //0101 0110 0111 1000
unsigned int bit1 = 0xf000; // 1111 0000 0000 0000
unsigned int bit2 = 0x0f00; // 0000 1111 0000 0000
unsigned int bit3 = 0x00f0; // 0000 0000 1111 0000
unsigned int bit4 = 0x000f; // 0000 0000 0000 1111
//and연산자를 사용하면 특정 비트열을 뽑아 낼 수 있다.
printf("결과 1 = %#.4x \n", data & bit1);
printf("결과 2 = %#.4x \n", data & bit2);
printf("결과 3 = %#.4x \n", data & bit3);
printf("결과 4 = %#.4x \n", data & bit4);
printf("\n");
//or 연산자를 사용하면 비트열의 일부를 변경시킬수 있다.
printf("결과 5 = %#.4x \n", data |= bit1);
printf("결과 6 = %#.4x \n", data |= bit2);
printf("결과 7 = %#.4x \n", data |= bit3);
printf("결과 8 = %#.4x \n", data |= bit4);
return 0;
}
[ 비트마스크 예제2]
#include <cstdio>
int main()
{
//2번째 비트를 1로 변경
// A | 1 << 2
printf("%#.4x\n", 0x1010 | 0x0100);
//2번째 비트를 0으로 변경
// A & ~1 << 2
printf("%#.4x\n", 0x1110 & 0x1011);
//2번째 비트의 값을 알 수 있는 방법
// A & (1<<i)
printf("2번째 비트의 값 = %d\n",0x1010 & 0x0100);
printf("3번째 비트의 값 = %d\n",0x1010 & 0x1000);
printf("%d\n", 0x1000111010 & (1<<0));
}
[ 비트마스크 예제3]
#include <cstdio>
int main()
{
printf("180 & (1<<0) = %d\n", 180 & (1<<0));
printf("180 & (1<<1) = %d\n", 180 & (1<<1));
printf("180 & (1<<2) = %d\n", 180 & (1<<2));
printf("180 & (1<<3) = %d\n", 180 & (1<<3));
printf("180 & (1<<4) = %d\n", 180 & (1<<4));
printf("---------------\n");
printf("180 | (1<<0) = %d\n", 180 | (1<<0));
printf("180 | (1<<1) = %d\n", 180 | (1<<1));
printf("180 | (1<<2) = %d\n", 180 | (1<<2));
printf("180 | (1<<3) = %d\n", 180 | (1<<3));
printf("180 | (1<<4) = %d\n", 180 | (1<<4));
printf("---------------\n");
printf("180 ^ (1<<0) = %d\n", 180 ^ (1<<0));
printf("180 ^ (1<<1) = %d\n", 180 ^ (1<<1));
printf("180 ^ (1<<2) = %d\n", 180 ^ (1<<2));
printf("180 ^ (1<<3) = %d\n", 180 ^ (1<<3));
printf("180 ^ (1<<4) = %d\n", 180 ^ (1<<4));
printf("---------------\n");
printf("180 & ~(1<<0) = %d\n", 180 & ~(1<<0));
printf("180 & ~(1<<1) = %d\n", 180 & ~(1<<1));
printf("180 & ~(1<<2) = %d\n", 180 & ~(1<<2));
printf("180 & ~(1<<3) = %d\n", 180 & ~(1<<3));
printf("180 & ~(1<<4) = %d\n", 180 & ~(1<<4));
return 0;
}
[ 비트마스크 예제4]
#include <cstdio>
int main()
{
int n;
scanf("%d", &n);
//전체집합 = (1<< n)-1 공집합은 제외
for (int i=1; i<(1<<n) ; i++)
{
printf("%d = ", i);
for (int k=0; k<n; k++)
{
// printf("%d", i & (1<<k));
if( i & (1<<k) )
printf("1");
else
printf("0");
}
printf("\n");
}
return 0;
}
[ 비트마스크 문제 풀기 ]
11723번: 집합
첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다. 둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.
www.acmicpc.net
1182번: 부분수열의 합
첫째 줄에 정수의 개수를 나타내는 N과 정수 S가 주어진다. (1 ≤ N ≤ 20, |S| ≤ 1,000,000) 둘째 줄에 N개의 정수가 빈 칸을 사이에 두고 주어진다. 주어지는 정수의 절댓값은 100,000을 넘지 않는다.
www.acmicpc.net
12813번: 이진수 연산
총 100,000 비트로 이루어진 이진수 A와 B가 주어진다. 이때, A & B, A | B, A ^ B, ~A, ~B를 한 값을 출력하는 프로그램을 작성하시오.
www.acmicpc.net
2098번: 외판원 순회
첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 16) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j
www.acmicpc.net
1562번: 계단 수
첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.
www.acmicpc.net
'C언어 자료구조' 카테고리의 다른 글
[ccw] ccw - 선분교차 (0) | 2023.08.03 |
---|---|
[유니온 파인드] 유니온 파인드란? - 5문제 (0) | 2021.03.08 |
[트리 1일차] 트리의 정의 및 용어 (0) | 2021.03.04 |
[우선순위 큐 1일차] - 9문제 (0) | 2021.02.25 |
[우선순위 큐 2일차] - 9문제 (0) | 2021.02.22 |