[C Programming] if문 활용해보기.


백준 알고리즘 단계별 풀어보기.

단계별 풀어보기 4번째 항목에 있는 if문 사용해보기의 문제를 풀어본 것을 게시하고자 합니다.

생각보다 if문이나 이전에 게시했던 for문은 우리가 당연히 간단하게 사용하고 있었던 코드의 요소들 중 하나라고 생각하고 있었으나 문제만 보아도 꽤나 복잡한 점을 볼 수 있었습니다.

결코 이 조건문과 반복문도 전혀 쉽지 않다는 것을 여러모로 느꼈습니다.
또한, 이 조건문과 반복문의 활용은 어떻게 하느냐에 따라 다르다는 것을 느꼈습니다. 이 두 가지만 있으면 그 어떤 코드도 짤 수는 있지 않을까라는 생각이 들기도 하였습니다.

여전히 코드를 짜는 것은 힘들고 여러 오픈 소스를 참고하고 있습니다. 코드를 스스로 손 쉽게 짜는 날까지 더 공부하고 더 많은 코드를 짜볼 필요가 있다는 것을 생각해봅니다.

if문 단계의 문제들은 많지 않으나 결코 쉽지 않은 잊지 말아야할 그런 항목들의 문제가 있었습니다.

9438번 문제

문제

시험 점수를 입력받아 90~100점은 A, 80~89점은 B, 70~79점은 C, 60~69점은 D, 나머지 점수는 F를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 시험 점수가 주어진다. 시험 점수는 0보나 크거나 같고, 100보다 작거나 같은 자연수이다.

출력

시험 성적을 출력한다.

예제 입력

100

예제 출력

A

코드

#include <stdio.h>
int main() {

int a;
scanf("%d", &a);

if(a>=90)
  printf("A");
else if(a>=80)
  printf("B");
else if(a>=70)
  printf("C");
else if(a>=60)
  printf("D");
else
  printf("F);

}

코드 자체는 비교적 간단한 형태입니다. 조금 더 고급 프로그래밍은 아마 점수 입력에 따라 자동으로 성적을 출력해주는 더 효율적인 코드가 있을 것 같습니다. 하지만 저는 아직 실력이 모자라서 단순 범위에 대한 조건을 준 조건문으로 코드를 완성해 보았습니다.

10817번 문제

문제

세 정수 A, B, C가 주어진다.  이 때, 두 번째로 큰 정수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 세 정수 A, B, C가 공백으로 구분되어 주어진다. (1 ≤ A, B, C ≤ 100)

출력

두 번째로 큰 정수를 출력한다.

예제 입력

20 30 10

예제 출력

20

코드

#include<stdio.h>

int main() {

 int a,b,c;
 scanf("%d %d %d", &a, &b,  &c);

 if((b<=a && a<=c) || (c<=a && a<=b))
   printf("%d\n", a);
 else if((a<=b && b<=c) || (c<=b && b<=a))
   printf("%d\n", b);
 else
   printf("%d\n", c);

}

이번 코드도 저는 처음에 입력되는 숫자의 순서에 따라 출력하게 하려다가 두 번째로 큰 정수가 처음에 입력되거나 세번째에 입력될 수도 있을 것 같아서 몇 번째로 입력되던간에 서로 비교해서 두 번째로 큰 정수를 나타나게끔 하였습니다. 더 좋은 방법은 정렬 알고리즘을 하나 만들어서 숫자의 크기 순으로 정렬된 값을 배열에 저장해서 두 번쨰 인덱스에 있는 값을 출력하는 코드를 만들면 더 좋은 프로그램이 되지 않을까 생각해보았습니다.
하지만.. 아직 실력이 많이 모자르네요. 더 많이 공부해야 할 것 같습니다. 

10871번 문제

문제

정수 N개로 이루어진 수열 A와 정수 X가 주어진다. 이 때, A에서 X보다 작은 수를 모두 출력하는 프로그램을 작성하십시오.

입력

첫째 줄에 N과 X가 주어진다.  (1 ≤ N, X ≤ 10,000)
둘째 줄에 수열 A를 이루는 정수 N개가 주어진다. 주어지는 정수는 모두 1보다 크거나 같고, 10,000보다 작거나 같은 정수이다.

출력

X보다 작은 수를 입력받은 순서대로 공백으로 구분해 출력한다.  X보다 작은 수는 적어도 하나 존재한다.

예제 입력

10 5
1 10 4 9 2 3 8 5 7 6

예제 출력

1 4 2 3

코드

#include<stdio.h>
int main() {
  int n,x,tmp;
  scanf("%d %d", &n, &x);

  for(int i=0; i<n; i++) {
     scanf("%d", &tmp);
     if(tmp<x) {
       printf("%d ", tmp);
     }
  }
}

아마 문제가 복잡해지기 시작한 문제가 이 문제부터 시작된 것 같다. 처음에 변수로 n과 x, tmp를 만들고 n과 x에 수열 A와 정수 X를 입력하고 그 다음 for문을 통해 입력받은 수열 A만큼 반복문을 돌리고 수열 A의 크기만큼 값들을 입력한다.

그리고 이 때, 정수 X보다 작은 값이 존재한다면 그 값을 출력하고 n의 크기만큼 반복문을 돌린다. 비교적 간단해 보이지만 여기서부터 꽤 골머리를 썩었던 것 같다. 처음에 작은 기준을 어떻게 나눠서 따로 빼면 좋을까 고민을 했었는데, 원하는 답이 오랫동안 나오지 않았던 것 같다. 결국 여러 소스들을 보면서 조금씩 이해가 되었던 것 같다.

1546번 문제

문제

세준이는 기말고사를 망쳤다.  세준이는 점수를 조작해서 집에 가져가기로 했다. 일단 세준이는 자기 점수 중에 최대값을 골랐다. 이 값을 M이라고 한다. 그리고 나서 모든 점수를 점수/M*100이 되어 71.43점이 된다. 세준이의 성적을 위의 방법대로 새로 계산했을 때, 새로운 평균을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 시험 본 과목의 개수 N이 주어진다. 이 값은 1000보다 작거나 같다. 둘째 줄에 세준이의 현재 성적이 주어진다. 이 값은 100보다 작거나 같은 음이 아닌 정수이고, 적어도 하나의 값은 0보다 크다.

출력

첫째 줄에 새로운 평균을 출력한다. 정답과의 절대/상대 오차는 10의 -2승 까지 허용한다.

예제 입력

3
40 80 60

예제 출력

75.00

코드

#include<stdio.h>
int main() {
  int n;
  scanf("%d", &n);

  int max = 0;
  float sum = 0.0;

  int score[1000] = {0, };

  for(int i=0; i<n; i++) {
      scanf("%d", &score[i]);
      if(max<score[i])
         max=score[i];
   }
   for(int i=0; i<n;  i++)
      sum += ((float)score[i]/(float)max)*100;

   printf("%.2lf", sum/(float)n);'
}

이 문제 또한 주어진 조건의 형식만 갖춰준다면 어렵지 않을 수 있으나, 그 조건을 갖추기 위한 틀을 짜는 게 쉽지 않은 부분이었던 것 같다. 코드를 짤 때 '이렇게 하면 되겠다.' 라는 생각을 제대로 갖추는 게 중요하다고 본다. 어떤 형식으로 짜면 좋을지 매번 생각하게 된다. 그리고 부족한 부분이 항상 나오게 되니까, 고치고 고치고 반복하게 되는 것 같다. 백준 문제중에서 쉽게 넘어가는 문제가 그렇게 많지가 않은 편이다.

위의 코드는 먼저 과목 갯수 N을 입력받기 위해 변수 n을 두고 입력된 점수중에서 최대 점수를 저장하기 위한 max 변수를 둔다. 그리고 평균 값의 합을 저장하기 위해 sum 변수를 선언한다. 그리고 입력받은 점수를 저장하기 위해 score 배열을 선언한다.

그리고 왠만하면 모든 초기화를 null로 해주는 편이다. 여러모로 이 부분이 전체적인 코드를 바람직하게 짤 수 있다고 배웠던 것 같다.

그 다음 입력한 과목 갯수만큼 for문을 돌린다.  그리고 그 과정에서 score 배열에 점수를 입력시킨다. 이 상황에서 입력한 점수 값이 max 변수에 들어간 최대 값보다  클 경우 score[i]의 값이 max에 들어가게 된다. 일단 max가 0으로 초기화 된 상태이니까, score[0]의 값은 무조건 max의 초기값이  될 것이다. 그 이후에 비교하면서 새로운 max가 나오지 않는다면 score[0]의 값을 유지할 것이다.

그리고 그 다음 for문에서 점수와 최대값을 나누고  그 값에 100을 더한 것을 모두 sum 변수에 더해주고  그 최종 값을 과목 갯수만큼 나눠주면 새로운 평균 값을 도출해낼 수 있습니다.  .2lf를 통해서 소수점 둘째 자리까지 나타낼 것입니다.

개인적으로 꽤나 복잡한 문제였습니다.

4334번 문제

문제

대학생 새내기들의 90%는 자신이 반에서 평균은 넘는다고 생각한다. 당신은 그들에게 슬픈 진실을 알려줘야 한다.

입력

첫째 줄에는 테스트케이스 C가 주어진다.
둘째 줄부터 각 테스트케이스 마다 첫 수로 정수 N(1<=N<=1000)명의 학생이 주어지고 그 다음으로 N명의  0부터 100 사이의 점수가 이어서 주어진다.

출력

각 케이스마다 한줄씩 평균을 넘는 학생들의 비율을 소수점 넷째자리에서 반올림하여 출력한다.

예제 입력

5
5 50 50 70 80 100
7 100 95 90 80 70 60 50
3 70 90 80
3 70 90 81
9 100 99 98 97 96 95 94 93 91

예제 출력

40.000%
57.143%
33.333%
66.667%
55.556%


코드

#include<stdio.h>
int main() {
  int score[1000];
  double average[1000];
  int n;
  scanf("%d", &n);
  for(int i = 0; i<n; i++) {
      int sum = 0;
      int average1 = 0;
      int sum1 = 0;
      int c;

      scanf("%d", &c);
      for(int j=0; j<c; j++) {
           scanf("%d", &score[j]);
      }
      for(int k=0; k<c; k++) {
          sum += score[k];
      }
      average1 = sum / c;
      for(int m=0; m<c; m++) {
          if(score[m]>average1)
            sum++;
       }
       average[i] = ((double)sum1 / (double)c)*100;
}
for(int i=0; i<n; i++)
   printf("%.3lf%%\n", average[i]);


이 코드 또한 상당히 복잡한 코드였던 것 같습니다. 먼저 점수를 입력받을 스코어 배열과 평균을 저장할 에버리지 배열을 선언하고 변수 n을 만들어 테스트케이스 C를 n으로 입력받습니다. 그리고 테스트 케이스의 크기만큼 for문을 돌리는데, 안에서 sum, sum1, average1 변수들을 선언하고 0으로 초기화시켜 줍니다.

그 이후에 테스트 케이스 안에서 과목 갯수를 입력받을 변수 c를 만들고 변수 c에 과목 갯수를 입력받습니다.  그리고 그 다음 for문에서 과목 갯수만큼 점수를 입력받고 입력받은 점수를 전부 sum 변수에 더해서 저장합니다. 그리고 이 저장된 값을 과목 갯수 값으로 나누어줍니다. 그리고 이 값을 average1 변수에 저장합니다.

그리고 그 다음 for문에서 score 배열에 저장된 값들 중에서 average1 값보다 높은 갯수를 sum1 변수에 카운트 시켜줍니다.

그리고 average 배열의 각 인덱스에 double 형으로 형변환한 높은 갯수를 카운트시킨 sum1 변수와 과목 갯수를 나눈 값에 100을 곱한 결과 값을 저장시켜 줍니다.

그리고 for문을 빠져나와서 최종 for문에서 출력 반복문을 돌려주면 마무리됩니다.

%%를 써줌으로써 %를 나타내고 .3lf를 써줌으로써 소수점 셋째 자리까지 출력시켜 줍니다.

저는 if문 사용해보기 단계에서 두 번째로 가장 복잡한 문제가 아니었나 생각이 드는 문제였습니다. 제일 복잡한 문제는 마지막 문제인 것 같습니다..

1110번 문제

문제

0보다 크거나 같고, 99보다 작거나 같은 정수가 주어질 때 다음과 같은 연산을 할 수 있다. 먼저 주어진 수가 10보다 작다면 0을 붙여 두 자리 수로 만들고, 각 자리의 숫자를 더한다. 그 다음, 주어진 수의 가장 오른쪽 자리 숫자와 앞에서 구한 합의 가장 오른쪽 자리 숫자를 이어 붙이면 새로운 수를 만들 수 있다. 다음 예를 보자.

26부터 시작한다. 2+6=8이다. 새로운 숫자는 68이다. 6+8=14이다. 새로운 숫자는 84이다. 8+4=12이다. 새로운 숫자는 42이다. 4+2=6이다. 새로운 숫자는 26이다.

위의 예는 4번만에 원래 숫자로 돌아올 수 있다. 따라서 26의 사이클의 길이는 4이다.
N이 주어졌을 때, N의 사이클의 길이를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. N은 0보다 크거나 같고, 99보다 작거나 같은 정수이다.

출력

첫째 줄에 N의 사이클 길이를 출력한다.

예제 입력

26

예제 출력

4

코드

#include<stdio.h>
int main() {
    int n;
    scanf("%d", &n);
 
    int count = 0;
    int a, b, c, add;
    add = n;

    while(add != n || count == 0) {
           a = add / 10;
           b = add % 10;
           c = (a+b) % 10;
           a = b; b = c;
           add = a * 10 + b;
           count++;
     }

    printf("%d\n", count);
}

이  문제의 코드를 보면 처음에 숫자를 입력받을 변수 n을 통해 숫자를 입력받고 그 이후에 count 변수를 선언하고 초기화시켜준다. 그리고 변수 a, b, c, add를 선언하고 add에 n값을 대입시켜줍니다. 그리고 while문을 선언합니다.

while문의 조건으로 add가 n과 같지 않거나 또는 count가 0일때까지 반복하는 것으로 조건을 둡니다. 처음에는 add가 n과 같으나 count가 0이기 때문에 반복합니다. a 변수에는 입력받은 값의 10의 자리를 저장하기 위해 사용되괴 b 변수에는 1의 자리를 저장하기 위해 사용됩니다. 그리고 c 변수에는 a와 b의 합한 값의 1의 자리를 저장하기 위해 사용되고 그 다음 b값을 a에 대입하고 c 값을 b에 대입합니다. 그리고 a는 본래 b값이니 다음 값을 위해서는 b값의 10의 자리와 c값의 1의 자리가 필요하니까, b값을 a변수에 대입하였으니 a변수에10을 곱함으로써 b값을 10의 자리로 사용할 수 있고 c값이 b에 대입되었으니 1의 자리의 값으로 그대로 사용되어 다음 값으로 새로운 숫자를 얻을 수 있습니다. 그리고 새로운 숫자가 맨 처음 숫자가 될 때까지 count++이 되니까, while문을 벗어날 때의 count 값이 본래의 값으로 돌아오기 위해 걸리는 횟수의 최종 결과값이 되기 떄문에 그것을 출력하는 코드를 넣어주면 마무리가 됩니다.

규칙이 까다로우나 명확합니다. 주어진 규칙과 조건만 잘 성립해준다면 풀릴수 있는 문제인 것은 확실하나 생각보다 그 연결고리가 복잡해서 하나씩 맞출려고 하면 머리가 아픈 문제 또한 분명히 있는 것 같습니다. 이 문제를 푸는 것도 매우 까다롭지 않았나 생각이 듭니다.

이번 포스팅은 여기까지입니다.


댓글

이 블로그의 인기 게시물

[Data Base] 2. E/R 관계성 모델에 대하여..

[Data Base] 1-1 Data Base에 관하여...

[Spring Boot] 1.Spring Boot.. 개발환경 갖추기.