문제
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으로 표시하고, 스위치 상태 사이에 빈칸을 하나씩 둔다.
알고리즘 분류
시뮬레이션 문제는 항상 새로운 것 같다.
이러한 생각을 어떻게 해내시는지 정말 존경스럽다.
하지만 이러한 문제가 초등부 문제라니, 이것 역시 새로운 것 같다.
물론 제가 초등학생일 때에는 프로그래밍이라는 공부가 그렇게 잘 알려지지는 않았던 것 같다.
지금에서야 코딩 교육이니 인공지능 조기교육이라든지 미디어에서 접하는 경우가 많지만
그때는 개발자 라는 직업이 있는지도 몰랐으니까 말이다.
아무튼 오늘 리뷰할 문제는 백준 알고리즘 1244번 스위치 켜고 끄기 문제이다.
이 문제 역시 5년전에 풀었던 문제이기 때문에, 어떻게 코드를 작성하였는지는 물론이고, 이 문제를 풀었던 기억조차 없다. 하지만 최대한 기억을 꺼내보도록 하겠다.
5년 전의 나는 무엇을 하고 싶었던 것일까. 정말 궁금하다. 느낌상 아무런 관계없이 여러번의 맞았습니다를 넣어본것이 아마 코드 길이를 조금이라도 줄여보고자 했던 것 같다는 생각이 첫번째로 들고
정답 비율에 집착했기에 여러번 정답 코드를 넣은 것이 아닌가에 대한 의심이 들기도 한다.
일단 첫번째 정답코드이다.
#include<cstdio>
int a[101];
int main(){
int num,tc,s,sw,ct = 0;
scanf("%d",&num);
for(int i = 1 ; i <= num ; i++)
scanf("%d",&a[i]);
scanf("%d",&tc);
while(tc--){
scanf("%d %d",&s,&sw);
if(s == 1){
int t = 1;
for(int i = sw; i <= num ; i = sw*t){
if(a[i]) a[i] = 0;
else a[i] = 1;
t++;
}
}else if(s == 2){
int p = 0;
while(sw-p != 0 && sw+p != num+1){
if(a[sw-p] == a[sw+p]){
if(p == 0){
if(a[sw]) a[sw] = 0;
else a[sw] = 1;
}else{
if(a[sw-p]) a[sw-p] = 0;
else a[sw-p] = 1;
if(a[sw+p]) a[sw+p] = 0;
else a[sw+p] = 1;
}
p++;
}else break;
}
}
}
for(int i = 1 ; i <= num ; i++){
ct++;
if(ct < 20){
printf("%d ",a[i]);
}else if(ct == 20){
printf("%d\n",a[i]);
ct = 0;
}
}
puts("");
}
가독성이 그리좋은 것은 아니지만 나쁘지 않게 풀어낸 것 같다.
그렇다면 마지막으로 제출한 정답코드를 봐보자.
#include<cstdio>
int a[101];
int main(){
int num,tc,s,sw,ct = 0;
scanf("%d",&num);
for(int i = 1 ; i <= num ; i++) scanf("%d",&a[i]);
scanf("%d",&tc);
while(tc--){
scanf("%d %d",&s,&sw);
if(s == 1){
for(int i = sw; i <= num ; i = sw*++s){
if(a[i]) a[i] = 0;
else a[i] = 1;
} }else if(s == 2){
int p = 0;
while(sw-p != 0 && sw+p != num+1){
if(a[sw-p] == a[sw+p]){
if(p == 0){
if(a[sw]) a[sw] = 0;
else a[sw] = 1;
}else{
if(a[sw-p]) a[sw-p] = 0;
else a[sw-p] = 1;
if(a[sw+p]) a[sw+p] = 0;
else a[sw+p] = 1;
} p++;
}else break; }}}
for(int i = 1 ; i <= num ; i++){
ct++;
if(ct < 20) printf("%d ",a[i]);
else if(ct == 20){
printf("%d\n",a[i]);
ct = 0;
}}puts("");}
정말 나쁜 코딩 습관을 그대로 넣어놓은 것 같다.
어디서부터 어디까지가 그룹인지도 모르겠고
프로그램의 끝 부분도 제대로 입력이 안 된 것 처럼 한방에 몰아넣어놨다.
역시, 코드 길이를 줄이기 위해서 이러한 짓을 벌인 것 같다.
이런 코딩 습관은 너무나도 안 좋기 때문에 따라하시면 안 됩니다.
최소한 첫번째 코드 처럼 작성이 되어야 합니다.