본문 바로가기
PS/BOJ

[자바] 백준 21918 - 전구 (java)

by Nahwasa 2022. 7. 28.

문제 : boj21918


 

필요 알고리즘 개념

  • 입력받기, 배열, 반복문, 조건문
    • 배열에 입력을 받고 조건문과 반복문을 쓸줄 알면 된다.
  • 시뮬레이션
    • 별건 아니고, 그냥 구현하란 말과 동일하다. 문제에서 제시된 사항을 그대로 구현해서 그대로 실행만 되면 된다. 참고로 백준에서 '구현'태그는 대강 뭐 특별히 쓸거 없을때 달아두는 경우가 많다 ㅋㅋ 그 중에 문제에서 제시된대로 구현만 잘 하면 되는 경우 보통 시뮬레이션 태그도 같이 단다. 사람마다 다를 수 있다. 내 경우엔 그렇다.

※ 제 코드에서 왜 main 함수에 로직을 직접 작성하지 않았는지, 왜 Scanner를 쓰지 않고 BufferedReader를 사용했는지 등에 대해서는 '자바로 백준 풀 때의 팁 및 주의점' 글을 참고해주세요. 백준을 자바로 풀어보려고 시작하시는 분이나, 백준에서 자바로 풀 때의 팁을 원하시는 분들도 보시는걸 추천드립니다.

 

 


 

풀이

  문제에서 제시된 대로만 구현해주면 되므로 딱히 풀이는 필요없을 것 같긴한데 그래도 쓸만한거 써보려 한다.

 

 

 

  우선 일반적으로 N개의 전구 정보는 배열로 받게될 것이다. 이 때, 배열의 인덱스는 알다시피 0부터 시작하지만 문제에서 제시되는 명령어는 i번째를 뜻한다. 즉, i번째의 배열 인덱스는 i-1번이 되게 된다(예를들어 1번째는 배열에서 0번 인덱스). 그럼 그냥 배열을 N개짜리로 선언하면 매번 입력받을 때 마다 명령어들의 인덱스를 -1 해줘야 하는 번거로움이 생긴다.

  그냥 단순하게 N+1개짜리 배열로 만들고, N개를 인덱스 1번부터 받아주게 되면 배열 1칸만큼의 메모리 손실은 나지만 그 뒤로 구현이 매우 편해진다. 이하 코드를 참고하자.

int[] arr = new int[n+1];

st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++)
    arr[i] = Integer.parseInt(st.nextToken());

 

 

  이후 들어오는 명령어들에 대해 a값을 기준으로 switch 또는 if 문을 통해 명령어를 구분하자. 이 때 처음 N개를 입력받은 배열을 arr이라고 하겠다.

 

1번 명령

-> 단순히 arr[b] = c 를 해주면 된다.

 

2번 명령

-> 반복문을 통해 arr[b]부터 arr[c]까지 0이면 1, 1이면 0으로 변경해주면 된다. 그렇다면 그냥 아래처럼 처리할 수 있다.

for (int i = b; i <= c; i++) {
    if (arr[i] == 0) 
    	arr[i] = 1;
    else arr[i] = 0;
}

 

  내 경우엔 arr[i]^=1 을 해줬다. '^'는 bitwise XOR(=비트단위 XOR. XOR=exclusive or)을 의미한다. XOR의 진리표는 다음과 같다. 보다시피 서로 다르다면 1, 같다면 0이다.

  예를들어 X ^ Y 라면 X와 Y의 각 비트단위로 XOR을(위의 표처럼 0과 1을 비트단위로 같은 자리끼리 비교) 진행한 결과를 내준다. 예를들어 X가 4라면 0100(2)이고, Y가 6이라면 0110(2)이다. 비트단위 XOR의 결과는 0010(2)이므로 결과는 2가 될 것이다.

 

  이 문제에서는 어차피 값 자체가 0 또는 1 이므로 bitwise XOR을 진행해도 그냥 변수 자체에 대한 XOR이라고 보면 된다. 아무튼 이걸로 왜 0이면 1, 1이면 0이 되냐면, 다음 주황색으로 칠한 부분 처럼 X ^ 1을 하게되면 X가 0일 땐 1이 되고, 1일땐 0이 되기 때문이다. 그냥 비트를 사용한 잡 기술 같은거다. 비슷한 예로 N이 짝수인지 홀수인지 판단은, N&1이 1이면 홀수, 0이면 짝수이다(bitwise AND).

 

3번 명령

-> 반복문을 통해 arr[b]부터 arr[c]까지 전부 0으로 변경해주면 된다.

 

4번 명령

-> 반복문을 통해 arr[b]부터 arr[c]까지 전부 1로 변경해주면 된다.

 

 

 

  이후 배열의 인덱스 1번부터 사용했으므로, 1번부터 순서대로 출력해주면 된다.

 


 

코드 : github

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    private void solution() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int[] arr = new int[n+1];

        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= n; i++)
            arr[i] = Integer.parseInt(st.nextToken());

        while (m-->0) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());
            switch (a) {
                case 1 :
                    arr[b] = c;
                    break;
                case 2 :
                    for (int i = b; i <= c; i++) arr[i]^=1;
                    break;
                case 3 :
                    for (int i = b; i <= c; i++) arr[i] = 0;
                    break;
                case 4 :
                    for (int i = b; i <= c; i++) arr[i] = 1;
                    break;
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= n; i++)
            sb.append(arr[i]).append(' ');
        System.out.println(sb);
    }
    public static void main(String[] args) throws Exception {
        new Main().solution();
    }
}

 

 

댓글