스위치 켜고 끄기

노누리·2022년 8월 1일
0

문제

1부터 연속적으로 번호가 붙어있는 스위치들이 있다. 스위치는 켜져 있거나 꺼져있는 상태이다. <그림 1>에 스위치 8개의 상태가 표시되어 있다. ‘1’은 스위치가 켜져 있음을, ‘0’은 꺼져 있음을 나타낸다. 그리고 학생 몇 명을 뽑아서, 학생들에게 1 이상이고 스위치 개수 이하인 자연수를 하나씩 나누어주었다. 학생들은 자신의 성별과 받은 수에 따라 아래와 같은 방식으로 스위치를 조작하게 된다.

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

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

예를 들어 <그림 2>에서 여학생이 3을 받았다면, 3번 스위치를 중심으로 2번, 4번 스위치의 상태가 같고 1번, 5번 스위치의 상태가 같으므로, <그림 3>과 같이 1번부터 5번까지 스위치의 상태를 모두 바꾼다. 만약 <그림 2>에서 여학생이 4를 받았다면, 3번, 5번 스위치의 상태가 서로 다르므로 4번 스위치의 상태만 바꾼다.

입력으로 스위치들의 처음 상태가 주어지고, 각 학생의 성별과 받은 수가 주어진다. 학생들은 입력되는 순서대로 자기의 성별과 받은 수에 따라 스위치의 상태를 바꾸었을 때, 스위치들의 마지막 상태를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에는 스위치 개수가 주어진다. 스위치 개수는 100 이하인 양의 정수이다. 둘째 줄에는 각 스위치의 상태가 주어진다. 켜져 있으면 1, 꺼져있으면 0이라고 표시하고 사이에 빈칸이 하나씩 있다. 셋째 줄에는 학생수가 주어진다. 학생수는 100 이하인 양의 정수이다. 넷째 줄부터 마지막 줄까지 한 줄에 한 학생의 성별, 학생이 받은 수가 주어진다. 남학생은 1로, 여학생은 2로 표시하고, 학생이 받은 수는 스위치 개수 이하인 양의 정수이다. 학생의 성별과 받은 수 사이에 빈칸이 하나씩 있다.

출력

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

예제 입력 1

8
0 1 0 1 0 0 0 1
2
1 3
2 3

예제 출력 1

1 0 0 0 1 1 0 1

문제 풀이

import java.util.Arrays;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int N=sc.nextInt();
		
		int[] arr=new int[N];
		for(int i=0;i<N;i++) {
			arr[i]=sc.nextInt();
		}
		
		int student=sc.nextInt();
		
		for(int s=0;s<student;s++) {
			int gender=sc.nextInt();
			int sw=sc.nextInt();
			
			if(gender==1) {
				int g=sw;
				while(g-1<arr.length) {
					if(arr[g-1]==0) {
						arr[g-1]=1;
					}else
						arr[g-1]=0;
					g+=sw;
				}
			}else if(gender==2) {
				int idx=1;
				
				if(arr[sw-1]==1) {
					arr[sw-1]=0;
				}else {
					arr[sw-1]=1;
				}
				
				while((sw-1-idx)>=0 && (sw-1+idx)<arr.length) {
					if(arr[sw-1-idx]==arr[sw-1+idx]) {
						if(arr[sw-1-idx]==1) {
							arr[sw-1-idx]=0;
							arr[sw-1+idx]=0;
							
						}else if(arr[sw-1+idx]==0) {
							arr[sw-1-idx]=1;
							arr[sw-1+idx]=1;
							
						}
						idx++;
					}
					else {
						break;
					}
				}
			}
		}
		
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+" ");
			if(i%20==19) {
				System.out.println();
			}
		}
	}

}

요즘 자바를 공부중인데 오랜만에 자바로 알고리즘을 풀었다. 값을 입력받는 부분에서 낯설었을 뿐 파이썬이나 자바나 로직은 똑같기 때문에 생각보다 쉽게 풀 수 있었다.

문제에 나온 순서대로 차근차근 구현해보면 완성된다.

스위치 상태를 배열에 넣어둔 뒤 남학생, 여학생 나누어 로직을 짠다.

남학생은 본인이 받은 스위치 번호의 배수의 번호를 스위치 누르는 것으로 반복문을 돌리면서 인덱스+처음 받은 스위치 번호 를 해주면 배수의 번호가 선택된다. 이후 if문을 통해 스위치를 눌러준다.

여학생은 본인을 중심을 왼쪽, 오른쪽으로 하나씩 뻗어나가 비교하고 왼쪽, 오른쪽 값이 같은 경우에 스위치를 눌러준다.

그렇게 반복한 후 마지막에 배열에 있는 값을 하나씩 뽑아 print한다. 이때 제한사항에 따라 20개가 한 줄에 출력되면 다음 줄로 넘어간다.
이때, 본인은 0번째 인덱스부터 시작하기 때문에 i%20==19인 경우에 println()를 해준다.


문제를 다 푼 후 제출을 눌렀더니 런타임 에러 (ArrayIndexOutOfBounds) 오류가 떴다. 배열의 범위를 벗어난 것 같은데 어디서 벗어난 것인지 알 수가 없어 하나씩 모두 확인해봤다.

남학생의 로직에서

while(g-1<arr.length) {
	if(arr[g-1]==0) {
		arr[g-1]=1;
	}else
		arr[g-1]=0;
	g+=sw;
}

이 부분을

for(int g=sw;g<arr.length;g+=g){
	if(arr[g-1]==0) {
		arr[g-1]=1;
	}else
		arr[g-1]=0;
}

이 코드로 작성했더니 오류가 발생했다.
이후에 for(int g=sw;g-1<arr.length;g+=sw) 처럼 조건을 바꾸니 문제가 성공했다! for문의 조건에서 오류가 발생했던 것 같다.

profile
백엔드 개발자입니다.

0개의 댓글