[Silver IV] 스위치 켜고 끄기 - 1244

JYC·2025년 7월 21일

[BAEKJOON]

목록 보기
102/102

문제 설명: 문제 링크

성능 요약

메모리: 15832 KB, 시간: 120 ms

분류

구현, 시뮬레이션

제출 일자

2025년 7월 21일 11:22:47


어떻게 풀 수 있을까?

해당 문제 로직은 크게 두 가지로 나뉜다.

첫번째는 남학생.

“스위치 번호가 자기가 받은 수의 배수이면, 그 스위치의 상태를 바꾼다. 즉, 스위치가 켜져 있으면 끄고, 꺼져 있으면 켠다. <그림 1>과 같은 상태에서 남학생이 3을 받았다면, 이 학생은 <그림 2>와 같이 3번, 6번 스위치의 상태를 바꾼다.”

→ 스위치 번호를 입력 받아 해당 스위치 번호를 따로 저장한 후, while문을 통해 스위치 번호에 해당하는 값을 조건문을 통해 바꾼 후 따로 저장한 스위치 번호 값을 + 해주는 방식으로 스위치 번호 수의 배수를 변경해나가면 된다.

두번째는 여학생.

”여학생은 자기가 받은 수와 같은 번호가 붙은 스위치를 중심으로 좌우가 대칭이면서 가장 많은 스위치를 포함하는 구간을 찾아서, 그 구간에 속한 스위치의 상태를 모두 바꾼다. 이때 구간에 속한 스위치 개수는 항상 홀수가 된다.”

→ 처음엔 count 라는 변수를 1로 지정해놓고, 스위치 번호 - count스위치 번호 + count 를 비교해 같으면 count의 값에 + 1을 한 후 비교하는 것을 반복하도록 설정했으나, 런타임 에러(배열 인덱스 길이 초과)가 나옴.

→ 해당 값들을 비교할 수 있는 ‘범위’를 지정해두고, 그 범위 내에서 값들을 비교하도록 변경하면 런타임 에러에서 안전하게 비교할 수 있음!

그리고

“스위치의 상태를 1번 스위치에서 시작하여 마지막 스위치까지 한 줄에 20개씩 출력한다. 예를 들어 21번 스위치가 있다면 이 스위치의 상태는 둘째 줄 맨 앞에 출력한다. 켜진 스위치는 1, 꺼진 스위치는 0으로 표시하고, 스위치 상태 사이에 빈칸을 하나씩 둔다.”

→ 출력에 주의하자! count 변수를 지정해 if 조건문으로 처리함.


처음 짠 코드 (런타임 에러)

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

public class Main {
    static int n,k;
    static int[] num;
    public static void main(String[] args) throws IOException {
       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        StringBuilder sb = new StringBuilder();

        n = Integer.parseInt(br.readLine());

        num = new int[n+1];
        num[0] = Integer.MAX_VALUE;
        st = new StringTokenizer(br.readLine());
        for(int i = 1; i <= n; i++){
            num[i] = Integer.parseInt(st.nextToken());
        }

        k = Integer.parseInt(br.readLine());
        for(int i=0; i<k; i++){
            st = new StringTokenizer(br.readLine());
            int gender = Integer.parseInt(st.nextToken());
            int switchNum = Integer.parseInt(st.nextToken());
            if(gender == 1){ //남자
                int count = switchNum;
                while(switchNum <= n){
                    num[switchNum] = num[switchNum] == 0 ? 1 : 0; //스위치 상태가 0이면 1로, 1이면 0 으로
                    switchNum += count;
                }
            }
            else{ //여자
                int count = 1;
                while(true){
                    if(switchNum - count < 1 || switchNum + count > n){
                        break;
                    }
                    if(num[switchNum - count] == num[switchNum + count]){
                        count++;
                    }
                    else{
                        count--;
                        break;
                    }
                }

                for(int j=switchNum-count; j<=switchNum + count; j++){
                    num[j] = num[j] == 0 ? 1 : 0;
                }
            }
        }

        int count = 0;
        for(int i=1; i<=n; i++){
            if(count >= 20){
                count = 0;
                sb.append("\n");
            }
            sb.append(num[i] + " ");
            count++;
        }

        System.out.println(sb.toString());
    }
}

왜 실패했는가?

여학생 로직의 경우에서 문제가 됐다.

int count = 1;
while(true){
    if(switchNum - count < 1 || switchNum + count > n){
        break;
    }
    if(num[switchNum - count] == num[switchNum + count]){
        count++;
    }
    else{
        count--;
        break;
    }
}

for(int j=switchNum-count; j<=switchNum + count; j++){
    num[j] = num[j] == 0 ? 1 : 0;
}

예를 들어

2
1 1
3
1 1
2 1
2 2

와 같은 입력이 주어졌다고 해보자.

문제가 될 수 있는 부분인 2 2 이다.

이 경우,학생은 여자이며 switchNum이 2라는 값을 받게 된다.

그렇다면 while문 안에 들어감과 동시에

if(switchNum - count < 1 || switchNum + count > n){
	break;
}

이 if문 조건에서 걸려 break 문으로 빠져나오게 되고, count는 그대로 1이 된다.

배열 인덱스의 범위는 2까지인데, switchNum은 2, count는 1인 상황이므로

for(int j=switchNum-count; j<=switchNum + count; j++){
    num[j] = num[j] == 0 ? 1 : 0;
}

해당 로직에서 인덱스 범위를 벗어난 3까지 for문을 돌리게 된다.

즉 런타임 에러가 나오게 된다.


코드 수정 + 코드 리팩토링 (통과 코드)

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

public class Main {
    static int n,k; //스위치 개수 , 학생 수
    static int[] num; //스위치 상태 표시 배열
    static StringBuilder sb = new StringBuilder();
    public static void main(String[] args) throws IOException {

       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        n = Integer.parseInt(br.readLine());

        num = new int[n+1];
        num[0] = Integer.MAX_VALUE; //스위치 상태 0번은 사용 X

        //스위치 상태 넣어주기.
        StringTokenizer st = new StringTokenizer(br.readLine());
        for(int i = 1; i <= n; i++){
            num[i] = Integer.parseInt(st.nextToken());
        }

        //학생 수 입력 받기
        k = Integer.parseInt(br.readLine());
        for(int i=0; i<k; i++){
            st = new StringTokenizer(br.readLine());

            //각각 성별, 스위치 번호 입력 받기
            int gender = Integer.parseInt(st.nextToken());
            int switchNum = Integer.parseInt(st.nextToken());

            if(gender == 1){ //남자
                studentMan(switchNum);
            }
            else{ //여자
                studentWoman(switchNum);
            }
        }

        printSwitches();
    }
    public static void printSwitches(){

        int count = 0;
        for(int i=1; i<=n; i++){
            if(count >= 20){
                count = 0;
                sb.append("\n");
            }
            sb.append(num[i] + " ");
            count++;
        }

        System.out.println(sb.toString());
    }

    public static void studentWoman(int switchNum){

        /*
        최대 범위를 설정함. 
        예: 만약 switchNum이 3이고, n이 8이라면 최대로 비교할 수 있는 범위는 2임.
        즉 3을 기준으로 1,5번 2,4번 인덱스를 비교하는 것이 최대라고 설정해두면 런타임 에러(배열 인덱스 값 넘어섬)를 벗어날 수 있음.
         */
        int range = Math.min(switchNum - 1, n - switchNum);
        int count = 0;

        for(int j = 0; j<=range; j++){
            if(num[switchNum-j] == num[switchNum+j]){
                count = j;
            }
            else{
                break;
            }
        }

        for(int j = switchNum - count; j <= switchNum + count; j++){
            num[j] = num[j] == 0 ? 1 : 0;
        }
    }

    public static void studentMan(int switchNum){

        int count = switchNum;
        while(switchNum <= n){
            num[switchNum] = num[switchNum] == 0 ? 1 : 0; //스위치 상태가 0이면 1로, 1이면 0 으로
            switchNum += count;
        }
    }
}
profile
열심히 하기 1일차

0개의 댓글