smooth waters run deep

1d-1c/BOJ

11723_집합 (JAVA)

yeon_11 2020. 11. 25. 15:52
 

11723번: 집합

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다. 둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

www.acmicpc.net

 

① int형 정수 이용 (비트마스크)
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		StringTokenizer st;

		int n = Integer.parseInt(br.readLine());
		String command = "";
		int num = 0;
		int S = 0;

		for(int i=0; i<n; i++){
			st = new StringTokenizer(br.readLine());
			command = st.nextToken();

			if(st.hasMoreTokens())
				num = Integer.parseInt(st.nextToken());


			if(command.equals("add"))
				S = S | (1<<num);

			if(command.equals("remove"))
				S = S & ~(1<<num);

			if(command.equals("check")){
				if((S&(1<<num)) != 0)
					sb.append(1).append('\n');
				else
					sb.append(0).append('\n');
			}

			if(command.equals("toggle"))
				S = S ^ (1<<num);

			if(command.equals("all"))
				S = (1<<21)-1;

			if(command.equals("empty"))
				S = 0;

		}
		System.out.print(sb);
		br.close();
	}
}

int S = 0; 으로 선언하고, 명령에 따라 S의 비트마스크를 변경하며 진행하는 방법이다.

 

int형은 4Bytes=32Bits이므로, 0000 0000 0000 0000 0000 0000 0000 0000의 꼴로 나타낼 수 있다.

오른쪽부터 2의 0승, 1승, 2승 ... 32승 까지로 나타낼 수 있으며, 입력받는 x를 x승의 위치로 이동시켜 계산한다.

 

즉, 1 = 0000 0000 0000 0000 0000 0000 0000 0001 을 x만큼 왼쪽으로 이동하는 shift연산을 이용하여 x를 표현한다.

예: x=3이면, 1<<3으로 표현한다.

    1<<3은 0000 0000 0000 0000 0000 0000 0000 1000 으로 나타낼 수 있고, 이때 1은 2의 3승에 위치하게 된다.

 

 

 

1) add x -   S | (1<<x)

                     1<<x 는 x위치가 1을 의미한다.

                     S에 x가 있다면==S의 x위치가 1이라는 의미이고, 1 OR 1 = 1

                     S에 x가 없다면==S의 x위치가 0이라는 의미이고, 0 OR 1 = 1 로 해당 표현을 통해 무조건 결과는 1이 된다.

 

2) remove x -   S & ~(1<<x)

                             1<<x는 x위치가 1을 의미한다.

                             ~(1<<x)는 x위치만 0이고, 나머지 위치는 모두 1을 의미한다.

                             S에 x가 있다면==S의 x위치가 1일 때, S & ~(1<<x)를 수행하면 - 1 & 0 = 0

                             S에 x가 없다면==S의 x위치가 0일 때, S & ~(1<<x)를 수행하면 - 0 & 0 = 0 으로 결과는 무조건 0이 된다.

 

3) check x -   S & (1<<x) 의 값에 따라 출력을 달리 한다.

                          S에 x가 있다면==S의 x위치가 1일 때, S & (1<<x)의 값은 1 -> 1 출력

                          S에 x가 없다면==S의 x위치가 0일 때, S & (1<<x)의 값은 0 -> 0 출력

 

3) toggle x -   S ^ (1<<x)

                           문제의 'S에 x가 있으면 x를 제거하고, 없으면 x를 추가한다.'를 비트마스크로 보면,

                           'S에 x가 있으면 x를 제거하고' == S의 x위치의 값을 1->0 으로 변경하고

                           '없으면 x를 추가한다.' == S의 x위치의 값을 0->1로 변경해라. 라고 해석할 수 있다.

                           1<<x의 x위치는 1이므로,

                           S의 x위치=1 일때 (1<<x)과 연산하여 0의 결과를, S의 x위치=0 일때 (1<<x)와 연산하여 1의 결과가 나와야 한다.

                           이때 사용되는 연산은 XOR이 된다.

 

4) all -   (1<<21)-1

                1<<21 : 0000 0000 0010 0000 0000 0000 0000 0000

           -              1 : 0000 0000 0000 0000 0000 0000 0000 0001

          ---------------------------------------------------------------------------- 

                                0000 0000 0001 1111 1111 1111 1111 1110 

 

5) empty -   S=0

                        'S를 공집합으로 바꾼다.' == S=0

 

 

 

 

 

 

 

② boolean[] 배열 이용
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		StringTokenizer st;

		int n = Integer.parseInt(br.readLine());
		String command = "";
		int num = 0;
		boolean[] S = new boolean[21]; // x범위: 1~20

		for(int i=0; i<n; i++){
			st = new StringTokenizer(br.readLine());
			command = st.nextToken();

			if(st.hasMoreTokens())
				num = Integer.parseInt(st.nextToken());


			if(command.equals("add"))
				S[num] = true;

			if(command.equals("remove"))
				S[num] = false;

			if(command.equals("check")){
				if(S[num])
					sb.append(1).append('\n');
				else
					sb.append(0).append('\n');
			}

			if(command.equals("toggle"))
				S[num] = !S[num];

			if(command.equals("all"))
				Arrays.fill(S, true);

			if(command.equals("empty"))
				Arrays.fill(S, false);

		}
		System.out.print(sb);
		br.close();
	}
}

21크기로 boolean[]배열을 선언하여, 명령에 따라 해당 위치의 값을 true/false로 변경하는 방법이다.

 

 

1) add x -   S[x] = true로 변경

 

2) remove x -   S[x] = false로 변경

 

3) check x -   S[x]=true이면 1출력 / false이면 0출력

 

3) toggle x -   S[x] = !S[x]  (true->false / false->true로 변경)

 

4) all -   S[x]의 모든 값을 true로 변경  ==  Arrays.fill(S, true);

 

5) empty -   S[x]의 모든 값을 false로 변경  ==  Arrays.fill(S, false);

 

 

'1d-1c > BOJ' 카테고리의 다른 글

14501_퇴사 (JAVA)  (0) 2020.11.29
6603_로또 (JAVA)  (0) 2020.11.28
10972_다음 순열 & 10973_이전 순열 (JAVA)  (0) 2020.11.24
9095_1,2,3 더하기 (JAVA)  (0) 2020.11.24
14500_테트로미노 (JAVA)  (0) 2020.11.23