스위치 켜고 끄기
문제
1부터 연속적으로 번호가 붙어있는 스위치들이 있다. 스위치는 켜져 있거나 꺼져있는 상태이다. <그림 1>에 스위치 8개의 상태가 표시되어 있다. ‘1’은 스위치가 켜져 있음을, ‘0’은 꺼져 있음을 나타낸다. 그리고 학생 몇 명을 뽑아서, 학생들에게 1 이상이고 스위치 개수 이하인 자연수를 하나씩 나누어주었다. 학생들은 자신의 성별과 받은 수에 따라 아래와 같은 방식으로 스위치를 조작하게 된다.
남학생은 스위치 번호가 자기가 받은 수의 배수이면, 그 스위치의 상태를 바꾼다. 즉, 스위치가 켜져 있으면 끄고, 꺼져 있으면 켠다. <그림 1>과 같은 상태에서 남학생이 3을 받았다면, 이 학생은 <그림 2>와 같이 3번, 6번 스위치의 상태를 바꾼다.
여학생은 자기가 받은 수와 같은 번호가 붙은 스위치를 중심으로 좌우가 대칭이면서 가장 많은 스위치를 포함하는 구간을 찾아서, 그 구간에 속한 스위치의 상태를 모두 바꾼다. 이때 구간에 속한 스위치 개수는 항상 홀수가 된다.
스위치 번호 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧
스위치 상태 0 1 0 1 0 0 0 1
<그림 1>
예를 들어 <그림 2>에서 여학생이 3을 받았다면, 3번 스위치를 중심으로 2번, 4번 스위치의 상태가 같고 1번, 5번 스위치의 상태가 같으므로, <그림 3>과 같이 1번부터 5번까지 스위치의 상태를 모두 바꾼다. 만약 <그림 2>에서 여학생이 4를 받았다면, 3번, 5번 스위치의 상태가 서로 다르므로 4번 스위치의 상태만 바꾼다.
스위치 번호 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧
스위치 상태 0 1 1 1 0 1 0 1
<그림 2>
스위치 번호 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧
스위치 상태 1 0 0 0 1 1 0 1
<그림 3>
입력으로 스위치들의 처음 상태가 주어지고, 각 학생의 성별과 받은 수가 주어진다. 학생들은 입력되는 순서대로 자기의 성별과 받은 수에 따라 스위치의 상태를 바꾸었을 때, 스위치들의 마지막 상태를 출력하는 프로그램을 작성하시오.
입력
첫째 줄에는 스위치 개수가 주어진다. 스위치 개수는 100 이하인 양의 정수이다. 둘째 줄에는 각 스위치의 상태가 주어진다. 켜져 있으면 1, 꺼져있으면 0이라고 표시하고 사이에 빈칸이 하나씩 있다. 셋째 줄에는 학생수가 주어진다. 학생수는 100 이하인 양의 정수이다. 넷째 줄부터 마지막 줄까지 한 줄에 한 학생의 성별, 학생이 받은 수가 주어진다. 남학생은 1로, 여학생은 2로 표시하고, 학생이 받은 수는 스위치 개수 이하인 양의 정수이다. 학생의 성별과 받은 수 사이에 빈칸이 하나씩 있다.
출력
스위치의 상태를 1번 스위치에서 시작하여 마지막 스위치까지 한 줄에 20개씩 출력한다. 예를 들어 21번 스위치가 있다면 이 스위치의 상태는 둘째 줄 맨 앞에 출력한다. 켜진 스위치는 1, 꺼진 스위치는 0으로 표시하고, 스위치 상태 사이에 빈칸을 하나씩 둔다.
풀이
첫번째 오답
package unit01;
import java.util.*;
public class Main {
static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
//입력받기위한 scanner
int count=Integer.valueOf(scan.nextLine());
//스위시 상태 입력
String switchs=scan.nextLine();
String[] switchsArr=switchs.split("\\s");
//학생수 입력
int people=Integer.parseInt(scan.nextLine());
//학생수 만큼 for문 돌리기
for(int i=0;i<people;i++)
{
//스위치 상태 바꾸기
changeSwitchs(switchsArr);
}
//System.out.println(Arrays.toString(switchsArr));
for(int i=0;i<switchsArr.length;i++)
{
System.out.printf(switchsArr[i]+" ");
}
}
//숫자를 뒤집는 함수
public static String[] changeSwitchs(String[] arrSt)
{
//성별 및 스위치 번호 입력 받기
String input=scan.nextLine();
String[] inputArr=input.split("\\s");
//성별
int sex=Integer.parseInt(inputArr[0]);
//받은 숫자
int num=Integer.parseInt(inputArr[1]);
//여자일때 기존에 받은 값에서 -1 하기(배열때문에)
num=(sex==1)?num:num-1;
for(int i=0;i<arrSt.length;i++)
{ //남자일때
if(sex==1)
{
if(i>0 && num*i<arrSt.length && num!=0)
{
//배열때문에 입력값에 -1해주기
int numX=(num*i)-1;
//삼항연산자로 연산 입력한 수의 배수의 상태값을 바꾸기
arrSt[numX]=(arrSt[numX].equals("0"))?"1":"0";
}
}else {
//여자일때
//양짝 사이드로 숫자 변경...(받은 숫자에서 i만큼 더하고 뺀값이 0보다 작거나 같고 배열길이보다 작을때.+그 값이 서로 같으면 조건문 실행
if((0<=(num-i) && arrSt.length>(num+i)) && arrSt[num-i].equals(arrSt[num+i]))
{
//기존에 받은 숫자의 스위치 상태변경
arrSt[num]=(arrSt[num].equals("0"))?"1":"0";
//기존값에 i만큼 빼고 더한 위치의 스위치 상태변경
arrSt[num-i]=(arrSt[num-i].equals("0"))?"1":"0";
arrSt[num+i]=(arrSt[num+i].equals("0"))?"1":"0";
System.out.println("________________________________________"+i);
System.out.println((num+i)+","+(num-i));
System.out.println(arrSt[num+i]+","+arrSt[num-i]);
System.out.println("________________________________________"+i);
}
else
{
//아니면 반복문을 빠져나간다.
break;
}
}
}
System.out.println();
//반례 11111111
//반례 0입력..
return arrSt;
}
}
--예외 발생
8
1 1 1 1 1 1 1 1
2 4
입력시
출력=>0 0 0 1 0 0 0 1
4번째 문자가 변경안됨
->문제 이유
else {
//여자일때
//양짝 사이드로 숫자 변경...(받은 숫자에서 i만큼 더하고 뺀값이 0보다 작거나 같고 배열길이보다 작을때.+그 값이 서로 같으면 조건문 실행
if((0<=(num-i) && arrSt.length>(num+i)) && arrSt[num-i].equals(arrSt[num+i]))
{
//기존에 받은 숫자의 스위치 상태변경
arrSt[num]=(arrSt[num].equals("0"))?"1":"0";
//기존값에 i만큼 빼고 더한 위치의 스위치 상태변경
arrSt[num-i]=(arrSt[num-i].equals("0"))?"1":"0";
arrSt[num+i]=(arrSt[num+i].equals("0"))?"1":"0";
System.out.println("________________________________________"+i);
System.out.println((num+i)+","+(num-i));
System.out.println(arrSt[num+i]+","+arrSt[num-i]);
System.out.println("________________________________________"+i);
}
else
{
//아니면 반복문을 빠져나간다.
break;
}
}
}
이부분에 기존에 받은 숫자의 스위치 상태 변경이 여러번 되서 이런 문제가 발생하는것으로 파악됨
else {
//여자일때
//양짝 사이드로 숫자 변경...(받은 숫자에서 i만큼 더하고 뺀값이 0보다 작거나 같고 배열길이보다 작을때.+그 값이 서로 같으면 조건문 실행
if((0<=(num-i) && arrSt.length>(num+i)) && arrSt[num-i].equals(arrSt[num+i]))
{
if(i==0)
{
//기존에 받은 숫자의 스위치 상태변경
arrSt[num]=(arrSt[num].equals("0"))?"1":"0";
}else
{
//기존값에 i만큼 빼고 더한 위치의 스위치 상태변경
arrSt[num-i]=(arrSt[num-i].equals("0"))?"1":"0";
arrSt[num+i]=(arrSt[num+i].equals("0"))?"1":"0";
}
}
else
{
//아니면 반복문을 빠져나간다.
break;
}
}
}
수정했으나 이번에는 출력오류가 떴다
- 문제를 잘 읽어보니
출력 스위치가 20개가 넘어가면 20개씩 출력하고 21번째는 띄어서 출력해야한다고 적혀있는걸 봄..
//System.out.println(Arrays.toString(switchsArr));
for(int i=0;i<switchsArr.length;i++)
{
if(i==(switchsArr.length-1))
{
//만약...
if(i%20==0 && i!=0) {
System.out.println();
}
System.out.printf(switchsArr[i]);
}else
{
//20개씩 출력하고 한칸 띄워라..
if(i%20==0 && i!=0) {
System.out.println();
}
System.out.printf(switchsArr[i]+" ");
}
}
출력부분 수정...근데 뭔가 넘 코드가 더러워서 나중에 깔끔하게 정리해봐야겠다..
---또 틀림
반례
4
0 0 0 0
1
1 1
정답= 1 1 1 1
내 답=1 1 1 0
남학생이 1을 받았을때 잘못 출력됨..
:books: [원인]=>배열끝까지 접근을 못함.
for(int i=0;i<=arrSt.length;i++)
{ //남자일때
if(sex==1)
{
if(i>0 && num*i<=arrSt.length && num!=0)
{
//배열때문에 입력값에 -1해주기
int numX=(num*i)-1;
//삼항연산자로 연산 입력한 수의 배수의 상태값을 바꾸기
arrSt[numX]=(arrSt[numX].equals("0"))?"1":"0";
}
}
}
:books: [해결]=>for문 범위를 늘려줌
리팩토링
출력부분에 쓸데없는 코드가 있어서 수정함.
for(int i=0;i<switchsArr.length;i++)
{
System.out.printf(switchsArr[i]+" ");
// 20개씩 출력
if((i+1)%20==0 && i!=0) {
System.out.println();
}
}
마지막 인자 출력시 " "공백 삽입해서 출력오류가 나는줄 알고 조건문을 여러개 달았는데 그거와 상관없어서 간단하게 수정하였다.
최종 제출 답
import java.util.*;
public class Main {
static Scanner scan=new Scanner(System.in);
public static void main(String[] args) {
//입력받기위한 scanner
int count=Integer.valueOf(scan.nextLine());
//스위치 상태 입력
String switchs=scan.nextLine();
String[] switchsArr=switchs.split("\\s");
//학생수 입력
int people=Integer.parseInt(scan.nextLine());
//학생수 만큼 for문 돌리기
for(int i=0;i<people;i++)
{
//스위치 상태 바꾸기
changeSwitchs(switchsArr);
}
for(int i=0;i<switchsArr.length;i++)
{
System.out.printf(switchsArr[i]+" ");
// 20개씩 출력
if((i+1)%20==0 && i!=0) {
System.out.println();
}
}
}
//숫자를 뒤집는 함수
public static String[] changeSwitchs(String[] arrSt)
{
//성별 및 스위치 번호 입력 받기
String input=scan.nextLine();
String[] inputArr=input.split("\\s");
//성별
int sex=Integer.parseInt(inputArr[0]);
//받은 숫자
int num=Integer.parseInt(inputArr[1]);
//여자일때 기존에 받은 값에서 -1 하기(배열때문에)
num=(sex==1)?num:num-1;
for(int i=0;i<=arrSt.length;i++)
{ //남자일때
if(sex==1)
{
if(i>0 && num*i<=arrSt.length && num!=0)
{
//배열때문에 입력값에 -1해주기
int numX=(num*i)-1;
//삼항연산자로 연산 입력한 수의 배수의 상태값을 바꾸기
arrSt[numX]=(arrSt[numX].equals("0"))?"1":"0";
}
}else {
//여자일때
//양짝 사이드로 숫자 변경...(받은 숫자에서 i만큼 더하고 뺀값이 0보다 작거나 같고 배열길이보다 작을때.+그 값이 서로 같으면 조건문 실행
if((0<=(num-i) && arrSt.length>(num+i)) && arrSt[num-i].equals(arrSt[num+i]))
{
if(i==0)
{
//기존에 받은 숫자의 스위치 상태변경
arrSt[num]=(arrSt[num].equals("0"))?"1":"0";
}else
{
//기존값에 i만큼 빼고 더한 위치의 스위치 상태변경
arrSt[num-i]=(arrSt[num-i].equals("0"))?"1":"0";
arrSt[num+i]=(arrSt[num+i].equals("0"))?"1":"0";
}
}
else
{
//아니면 반복문을 빠져나간다.
break;
}
}
}
//반례 11111111
//반례 0입력..
return arrSt;
}
}
반례 모음
4
0 0 0 0
1
1 1
답
1 1 1 1
8
0 0 0 0 0 0 0 0
1
2 4
답
1 1 1 1 1 1 1 0
21
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1
2 4
답
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1
회고
- 조건문이 많이 들어가고 조건이 복잡하다.
- 테스트 케이스를 여러 번 해봐야한다.
- 삼항연산자가 아직 헷갈린다.
- 출력오류가 많이 난다! 문제 정확히 파악하는게 중요
'알고리즘 > 백준' 카테고리의 다른 글
10809번 알파벳 찾기 (1) | 2022.09.22 |
---|---|
1157번 단어공부[미해결] (0) | 2022.09.20 |
[백준] 9498번 시험 성적 문제 -java11 (0) | 2021.09.14 |