https://www.acmicpc.net/problem/15787
코드설명
BitMask(비트마스크)를 활용합니다.
문제를 읽다보면, k번째 앉은 사람을 k+1번째로 이동시킨다. 등등과 같은 작업들로 비트마스크의 Shifting을 이용하라는 것이구나 라는것을 알아챌 수 있습니다.
만약, 비트마스킹을 사용하지 않으면 어떻게 될까요?
먼저 [10^6][20] 의 공간을 사용합니다.
메모리는 512MB 제한으로 메모리는 부족하지 않습니다.
시간복잡도의 경우는 만약 command가 3 i 가 약 M번 (10^5)가 들어왔다고 가정합니다.
만약 비트마스킹을 활용하지 않을경우 매번 배열을 오른쪽으로 직접 이동시켜야하는데 이떄의 시간복잡도는 20번입니다. (20개의 일렬좌석) 20* 10^5 로 시간복잡도는 10^6 * 2 입니다. 시간복잡도도 초과하지 않으므로 충분히 이 로직을 사용가능합니다.
하지만, 비트마스킹을 사용한다면, 로직이 훨씬 더 간단합니다.
모든 이동로직이 단순한 Shifting으로 처리될 수 있기 떄문입니다.
그렇기에 비트마스킹을 사용한 것이지, 일반적인 구현을 사용해도 통과할 수 있는 문제입니다.
문제에서 가장 핵심은, command 2 번일 것 입니다.
int num = 0b11111;
System.out.println( 0b11111 & ~(1<<2) );
만약 11111 이라는 좌석이 존재하고, 3번쨰 좌석을 제거하고 싶습니다.
이떄, mask = ~(1<<2) 로 11011 의 mask를 만들어줍니다.
그 이후에 & 연산을 해주면 3번째 좌석은 비어지게 됩니다.
만약, 아무도 그자리에 안자있지 않을경우도 이미 비어있으므로 상관없습니다.
두번쨰 유의사항은, 총 기차의 총 좌석개수는 20개라는 점입니다. 그러므로 아래와 같이 mask를
mask = 0b011111111111111111111 과 같이 만들어서 & 연산해줍니다. 이렇게 되면 20개좌석만 남겠지요.
arr[trainIdx] = arr[trainIdx] << 1;
int mask = ~(1 << 20);
arr[trainIdx] = arr[trainIdx] & mask;
코드
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;
public class Main {
static int N, M, S, P, K, B, a, b;
static int answer = 0;
static int[] arr;
static HashSet<Integer> hashset = new HashSet<>();
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
// int num = 0b11111;
// System.out.println( 0b11111 & ~(1<<2) );
arr = new int[N];
for(int i=0;i<M;i++) {
st = new StringTokenizer(br.readLine());
int command = Integer.parseInt(st.nextToken());
int trainIdx = 0;
int seatIdx = 0;
if(command == 1 || command == 2) {
trainIdx = Integer.parseInt(st.nextToken()) - 1;
seatIdx = Integer.parseInt(st.nextToken()) - 1;
}
else if(command == 3 || command == 4) {
trainIdx = Integer.parseInt(st.nextToken()) - 1;
}
if(command == 1) {
arr[trainIdx] = arr[trainIdx] | 1 << seatIdx;
} else if(command == 2){
//하차시키는 방법. 1111 이 있다. 만약 3번쨰 좌석을 없애고싶다면,
// mask를 생성하자.
// 1. 모두 1인 mask를 하나 생성한다.
// 2. 특정 위치에 ~(1 << seat위치) 반전시킨다.
// 3. 기존 beatmask & mask를 하면 된다.
int mask = ~(1 << seatIdx);
arr[trainIdx] = arr[trainIdx] & mask;
} else if(command == 3) {
arr[trainIdx] = arr[trainIdx] << 1;
int mask = ~(1 << 20);
arr[trainIdx] = arr[trainIdx] & mask;
} else if(command == 4) {
arr[trainIdx] = arr[trainIdx] >> 1;
int mask = ~(1 << 20);
arr[trainIdx] = arr[trainIdx] & mask;
}
}
for(int i=0;i<N; i++) {
hashset.add(arr[i]);
}
System.out.println(hashset.size());
}
}
'알고리즘 > BitMasking' 카테고리의 다른 글
[백준] 13171 A - 분할 정복을 이용한 거듭제곱(Divide And Conquer) + 수학(Math) + 비트마스킹(BitMask) JAVA (0) | 2024.08.15 |
---|---|
[백준] 14939 불 끄기 - 비트마스킹(BitMasking) + 그리디(Greedy) + 순서강제하기 JAVA (0) | 2024.05.14 |