C/BaekJoon

[C] 백준 2920 - 음계 | BaekJoon

sngsp 2023. 7. 28. 04:31

문제

다장조는 c d e f g a b C, 총 8개 음으로 이루어져있다. 이 문제에서 8개 음은 다음과 같이 숫자로 바꾸어 표현한다. c는 1로, d는 2로, ..., C를 8로 바꾼다.

1부터 8까지 차례대로 연주한다면 ascending, 8부터 1까지 차례대로 연주한다면 descending, 둘 다 아니라면 mixed 이다.

연주한 순서가 주어졌을 때, 이것이 ascending인지, descending인지, 아니면 mixed인지 판별하는 프로그램을 작성하시오.

입력

첫째 줄에 8개 숫자가 주어진다. 이 숫자는 문제 설명에서 설명한 음이며, 1부터 8까지 숫자가 한 번씩 등장한다.

출력

첫째 줄에 ascending, descending, mixed 중 하나를 출력한다.

예제 입력 1

1 2 3 4 5 6 7 8

예제 출력 1

ascending

예제 입력 2

8 7 6 5 4 3 2 1

예제 출력 2

descending

예제 입력 3

8 1 7 2 6 3 5 4

예제 출력 3

mixed

예상 풀이방법

int형 8칸짜리 배열을 선언하여 각 배열에 숫자를 입력받아 저장하고

for문 반복을 사용하여 정렬과 비슷한 방법을 응용한다는 생각으로
if (arr[i] < arr[i + 1]) 이라든가
if (arr[i] > arr[i + 1]) 같은 걸 사용해서 앞, 뒤에 있는 배열이 본인보다 큰지 작은지를 판별한다.

  1. 1부터 8까지 증가하는지
  2. 8부터 1까지 감소하는지
  3. 어떤 규칙성도 가지고있지 않은지

세 가지를 판별하여 printf한다.

주의할 점은 1 미만이나 8 이상의 수가 쓰여질 경우 오류가 나오기 때문에
3번의 경우 else로 경우의 수를 두면 안될 것 같다.

그러므로 가장 큰 대전제를 사용할 때
정렬에서 썼던 방법을 응용하여 1~8 이내의 숫자일 경우에만 프로그램 실행을 이어가고
아닐 경우 return 0;를 사용하여 중단시켜야 할 것 같다.

1차 코드

#include <stdio.h>
#include <string.h>

int main() {
    int arr[8];

    // 배열의 길이만큼의 반복을 통한 숫자 입력받기
    for (int i = 0; i < 8; i++) {
        scanf("%d", arr[i]);
        if (arr[i] < arr[i + 1]) {

        }
    }
}

1차 결과

미실행

1차 진단

배열에서 좌항이 우항보다 큰지 작은지는 판별할 수 있었으나, 전체적으로 1씩 증가하거나 1씩 감소하는지 여부를 알 수 없었다.
정렬의 방법을 사용할 경우 위치가 바뀌기 때문에 정렬또한 사용할 수 없었다.

1차 해결 노력

1

8, 8

1, 그 외
총 3가지 경우의 수를 알아볼 수 있는 가장 간단하면서도 for문에서 쓰여지는 0, 1, 2, 3 등을 응용하여 해결할 수 있어야 했다.
상황에 따라서는 if문 내에서 while문을 두 번 사용하여 오름차순, 내림차순으로 될 때까지 찾아내고 어긋날 경우 mixed라는 결론을 내도 괜찮을 것 같다.

하지만 코드 중복이 많고 길이가 길어져서 다른 방법을 구상해보았다.

0번 인덱스에 1이 들어가고 1번 인덱스에 2가 들어가는 단순한 오름차순의 경우
arr[i]의 값은 i + 1이 된다.

내림차순의 경우, arr[i]의 값은 8 - i가 된다.

이러면 모든 배열을 검토할 수 있는 공통된 i가 나온다.

그렇다면 arr[i]에 대한 for문을 사용하여 0번 인덱스부터 7번 인덱스를 지칭할 수 있고
i + 1이나 8 - i를 사용하여 인덱스 내부의 값도 지칭할 수 있게 된다.

지칭하는 경우를 if문 처리하고
해당 내용이 아닐 경우 mixed라는 결론을 내면 될 것 같다.

2차 코드

#include <stdio.h>
#include <string.h>

int main() {
    int arr[8];

    // 배열의 길이만큼의 반복을 통한 숫자 입력받기
    for (int i = 0; i < 8; i++) {
        scanf("%d", arr[i]);
    }

    // 총 숫자가 8개이니 0 1 2 3의 4번의 숫자 교환법 필요
    for (int i = 0; i < 4; i++) {
        // 오름차순일 경우
        if (arr[i] == i + 1 && arr[7 - i] == 8 - i) {
            printf("ascending");
        }
        // 내림차순일 경우
        if (arr[i] == 8 - i && arr[7 - i] == i + 1) {
            printf("descending");
        }
        // 그 외 (Mixed일 경우)
        else {
            printf("mixed");
        }
    }
}

2차 결과

실행은 되나 입력 후 결과값이 아무것도 뜨지 않음

2차 진단

  1. else if를 사용하지 않아서 그런 것인가
  2. else에 괄호가 들어가서 그런가
  3. if끼리 중복되는 경우가 있는가

3차 코드

#include <stdio.h>
#include <string.h>

int main() {
int arr[8];

// 배열의 길이만큼의 반복을 통한 숫자 입력받기
for (int i = 0; i < 8; i++) {
    scanf("%d", arr[i]);
}

// 총 숫자가 8개이니 0 1 2 3의 4번의 숫자 교환법 필요
for (int i = 0; i < 4; i++) {
    // 오름차순일 경우
    if (arr[i] == i + 1 && arr[7 - i] == 8 - i) {
        printf("ascending");
    }
    // 내림차순일 경우
    else if (arr[i] == 8 - i && arr[7 - i] == i + 1) {
        printf("descending");
    }
    // 그 외 (Mixed일 경우)
    else
        printf("mixed");
}

}

3차 결과

실행은 되나 입력 후 결과값이 아무것도 뜨지 않음

3차 진단

직접 int가 0일 경우부터 직접 코드를 따라가보기로 함.

일단 판독하는 코드 자체에는 문제가 없음을 직접 써봄으로 알 수 있었다.

그렇다면 의심해야 할 곳은 printf 부분이었다.

  1. printf가 중복되게 출력중이다.

생각해보니 1 2 3 4 5 6 7 8 이라든가 8 7 6 5 4 3 2 1 이 입력되는 경우엔 딱 맞아 떨어지는게 맞는데
만약 8 7 6 4 5 3 2 1 처럼 4와 5만 위치가 바뀌어있다면 ascensing 3번에 마지막엔 descending이 된다.
근데 그렇다면 출력 결과가

ascending
ascending
ascending
descending
이렇게 나와야되는거아닌가?

아예 안나오는 것에서 알 수 없는 무언가가 단단히 잘못되어있음을 느끼고 다시 코드를 대입시키지 말고
하나씩 쪼개보기로 했다.

내가 사용한 if문의 경우 0, 1, 2, 3의 for문이 돌았을 때, 4번을 전부 만족시켜야만 오름차순, 내림차순임을 확인할 수 있었는데
무턱대고 printf를 박은 게 잘못이라는 생각이 들었다. 아까 생각했던 if끼리의 중복도 맞고 애초에 if에 대한 조건 자체가
성립이 안되니까 ascending descending 자체를 표기할 수 없었다.

그럼 각 if문의 경우에서 카운트를 추가하고 카운트가 4개라면 printf를 하는 방법으로 바꾸면 될 것 같다.

4차 코드

#include <stdio.h>
#include <string.h>

int main() {
    int arr[8];
    int ascending = 0;
    int descending = 0;

    // 배열의 길이만큼의 반복을 통한 숫자 입력받기
    for (int i = 0; i < 8; i++) {
        scanf("%d", arr[i]);
    }

    // 총 숫자가 8개이니 0 1 2 3의 4번의 숫자 교환법 필요
    for (int i = 0; i < 4; i++) {
        // 오름차순일 경우
        if (arr[i] == i + 1 && arr[7 - i] == 8 - i) {
            ascending++;
        }
        // 내림차순일 경우
        if (arr[i] == 8 - i && arr[7 - i] == i + 1) {
            descending++;
        }
    }
    // for문이 완전히 종료되고나서 if문을 사용한 printf
    if (ascending == 4) {
        printf("ascending");
    }
    if (descending == 4) {
        printf("descending");
    }
    else {
        printf("mixed");
    }
}

4차 결과

실행은 되나 입력 후 결과값이 아무것도 뜨지 않음

4차 진단

  1. printf가 최종 단계인데 최종 단계에 변화를 주어도 실행 결과가 동일하므로 초반 단계에 문제가 있었다고 판단.
  2. 배열의 선언과 그에 따른 scanf에는 문제가 없어보임
  3. 4 미만의 수로 해당 수를 비교하는 것 또한 문제가 없어보임.
  4. 그럼 답은 if문에서 틀렸을 수 밖에 없다고 생각함.
    for (int i = 0; i < 4; i++) {
        // 오름차순일 경우
        if (arr[i] == i + 1 && arr[7 - i] == 8 - i) {
            ascending++;
        }
        // 내림차순일 경우
        if (arr[i] == 8 - i && arr[7 - i] == i + 1) {
            descending++;
        }
    }

이 코드만 놓고 생각을 해보기로 했다. if문에서 무언가가 틀렸다는 가정하에.

생각해보니 int i = 0으로 시작했고 모든 수는 i를 가지고 내가 임의의 수를 추가해서
무조건 공식이 맞을 수 밖에 없도록 설정해놓았기 때문에 if에 대한 조건이 참임을 다시 한 번 증명할 무언가가 필요했다.

0번 인덱스가 이거고 7번 인덱스가 이거일 때 라고 쓰는 게 아니라
0번 인덱스가 이거일 때, 7번 인덱스를 증명할 내용이 0번 인덱스를 통해서 들어가야하는 것 같다.

그래야 참과 거짓을 가려낼 수 있지 무턱대고 7 - i 하면 무조건 참일 수 밖에 없지않나 싶다.

그래서 && 뒷부분을 삭제하고 arr[i] 에 대한 내용을 어떻게 증명할 수 있는지 고민해봐야한다.

오름차순일 경우
0번 인덱스 값이 1이면서 7번 인덱스 값이 8인 경우는 합이 9이다.

i = 0이라고 쳤을 때

arr[i] == i + 1 && arr[i] + arr[7 - i] = 9

내림차순일 경우
0번 인덱스 값이 8이면서 7번 인덱스 값이 1인 경우는 합이 9이다.
i = 0이라고 쳤을 때

arr[i] = 8 - i && arr[i] + arr[7 - i] = 9

이렇게 바꾸어보았다.

5차 코드

#include <stdio.h>

int main() {
    int arr[8];
    int ascending = 0;
    int descending = 0;

    // 배열의 길이만큼의 반복을 통한 숫자 입력받기
    for (int i = 0; i < 8; i++) {
        scanf("%d", arr[i]);
    }

    // 총 숫자가 8개이니 0 1 2 3의 4번의 숫자 교환법 필요
    for (int i = 0; i < 4; i++) {
        // 오름차순일 경우
        if (arr[i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            ascending++;
        }
        // 내림차순일 경우
        else if (arr[i] == 8 - i && arr[i] + arr[7 - i] == 9) {
            descending++;
        }
    }
    // for문이 완전히 종료되고나서 if문을 사용한 printf
    if (ascending == 4) {
        printf("ascending");
    }
    else if (descending == 4) {
        printf("descending");
    }
    else {
        printf("mixed");
    }
}

5차 결과

실행은 되나 입력 후 결과값이 아무것도 뜨지 않음

5차 진단

왜 안되는지 모르겠는데 그냥 똑같은 arr[i]가 무언가의 값일 경우를 조건으로 둬서 그런가 싶어서
앞뒤만 바꿔보면 어떨까 싶다.

그리고 단어 안쓰니까 string.h 도 삭제해본다. 혹시 모르니까.

if(arr[i] == i+1 && arr[i] + arr[7 - i] == 9){
    ascending++;
    }
else if(arr[7-i] ==  i+1 && arr[i] + arr[7-i] == 9){
    descending++;
    }

6차 코드

#include <stdio.h>

int main() {
    int arr[8];
    int ascending = 0;
    int descending = 0;

    // 배열의 길이만큼의 반복을 통한 숫자 입력받기
    for (int i = 0; i < 8; i++) {
        scanf("%d", arr[i]);
    }

    // 총 숫자가 8개이니 0 1 2 3의 4번의 숫자 교환법 필요
    for (int i = 0; i < 4; i++) {
        // 오름차순일 경우
        if (arr[i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            ascending++;
        }
        // 내림차순일 경우
        else if (arr[7 - i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            descending++;
        }
    }
    // for문이 완전히 종료되고나서 if문을 사용한 printf
    if (ascending == 4) {
        printf("ascending");
    }
    else if (descending == 4) {
        printf("descending");
    }
    else {
        printf("mixed");
    }
}

6차 결과

실행은 되나 입력 후 결과값이 아무것도 뜨지 않음

6차 진단

진짜 더 이상은 모르겠어서 노란 경고표시를 눌러봤다.

허허 반환값 무시라...
그렇다. 앤퍼센드를 빼먹었다.

문자열 풀다가 넘어오면서 자연스럽게 안쓰고 시작한 것 같은데

초반에 문제가 있는 걸 알면서도 발견못한거랑 시간버렸다는 생각에 손 끝이 저려오기 시작하는데

뭐 내가 못한 걸 어떡하나 싶기도 하다

저번에도 이런 적 있는데 이걸 또 실수했다.

앤퍼센드 넣고 다시 짜봤다.

7차 코드

#include <stdio.h>

int main() {
    int arr[8];
    int ascending = 0;
    int descending = 0;

    // 배열의 길이만큼의 반복을 통한 숫자 입력받기
    for (int i = 0; i < 8; i++) {
        scanf("%d", &arr[i]);
    }

    // 총 숫자가 8개이니 0 1 2 3의 4번의 숫자 교환법 필요
    for (int i = 0; i < 4; i++) {
        // 오름차순일 경우
        if (arr[i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            ascending++;
        }
        // 내림차순일 경우
        else if (arr[7 - i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            descending++;
        }
    }
    // for문이 완전히 종료되고나서 if문을 사용한 printf
    if (ascending == 4) {
        printf("ascending");
    }
    else if (descending == 4) {
        printf("descending");
    }
    else {
        printf("mixed");
    }
}

7차 실행 결과

1 2 3 4 5 6 7 8
ascending
8 7 6 5 4 3 2 1
descending
8 1 7 2 6 3 5 4
mixed

미흡했던 점

앤퍼센드 빼먹고 안쓰는 바보같은 짓

개선 방안

버릇이 될 때까지 뇌리에 깊게 새기기. 같은 실수를 반복한 부분이라 더 신경써서 유심히 항상 기본이라고 아는거라고 대충 안넘기기.

최종 코드

#include <stdio.h>

int main() {
    int arr[8];
    int ascending = 0;
    int descending = 0;

    for (int i = 0; i < 8; i++) {
        scanf("%d", &arr[i]);
    }

    for (int i = 0; i < 4; i++) {
        if (arr[i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            ascending++;
        }
        else if (arr[7 - i] == i + 1 && arr[i] + arr[7 - i] == 9) {
            descending++;
        }
    }
    if (ascending == 4) {
        printf("ascending");
    }
    else if (descending == 4) {
        printf("descending");
    }
    else {
        printf("mixed");
    }
}

백준 채점 결과

비고

빼먹은 & 을 추가했을 경우 정답 유무

1차 : 미실행
2차 : 오답
3차 : 컴파일 에러
4차 : 오답
5차 : 정답
6차 : 정답
7차 : 최종 정답