[백준 / C언어] 2621번 문제

Estelle·2023년 9월 19일

백준 C/C++언어

목록 보기
5/16

문제

근우는 오늘 재미있는 카드 게임을 배우고 있다. 카드는 빨간색, 파란색, 노란색, 녹색의 네 가지 색이 있고, 색깔별로 1부터 9까지 숫자가 쓰여진 카드가 9장씩 있다. 카드는 모두 36(=4x9)장이다. 근우가 배운 카드 게임은 36장의 카드에서 5장을 뽑고, 아래와 같은 규칙으로 정수를 계산하는 것이다.

각 카드는 다음과 같이 나타낸다. 카드의 색깔은 영어 대문자 R, B, Y, G로 나타내는데, R은 빨간색, B는 파란색, Y는 노란색, G는 녹색을 뜻한다. 예를 들어서 Y8은 노란색 8을 나타내고, B5는 파란색 5를 나타낸다.

<점수를 정하는 규칙>

  1. 카드 5장이 모두 같은 색이면서 숫자가 연속적일 때, 점수는 가장 높은 숫자에 900을 더한다. 예를 들어, 카드가 Y4, Y3, Y2, Y5, Y6 일 때 점수는 906(=6+900)점이다.

  2. 카드 5장 중 4장의 숫자가 같을 때 점수는 같은 숫자에 800을 더한다. 예를 들어, 카드가 B3, R3, B7, Y3, G3 일 때 점수는 803(=3+800)점이다.

  3. 카드 5장 중 3장의 숫자가 같고 나머지 2장도 숫자가 같을 때 점수는 3장이 같은 숫자에 10을 곱하고 2장이 같은 숫자를 더한 다음 700을 더한다. 예를 들어, 카드가 R5, Y5, G7, B5, Y7 일 때 점수는 757(=5x10+7+700)점이다.

  4. 5장의 카드 색깔이 모두 같을 때 점수는 가장 높은 숫자에 600을 더한다. 예를 들어, 카드가 Y3, Y4, Y8, Y6, Y7 일 때 점수는 608(=8+600)점이다.

  5. 카드 5장의 숫자가 연속적일 때 점수는 가장 높은 숫자에 500을 더한다. 예를 들어 R7, R8, G9, Y6, B5 일 때 점수는 509(=9+500)점이다.

  6. 카드 5장 중 3장의 숫자가 같을 때 점수는 같은 숫자에 400을 더한다. 예를 들어 R7, Y7, R2, G7, R5 일 때 점수는 407(=7+400)점이다.

  7. 카드 5장 중 2장의 숫자가 같고 또 다른 2장의 숫자가 같을 때 점수는 같은 숫자 중 큰 숫자에 10을 곱하고 같은 숫자 중 작은 숫자를 더한 다음 300을 더한다. 예를 들어, R5, Y5, Y4, G9, B4 일 때 점수는 354(=5X10+4+300)점이다.

  8. 카드 5장 중 2장의 숫자가 같을 때 점수는 같은 숫자에 200을 더한다. 예를 들어, R5, Y2, B5, B3, G4 일 때 점수는 205(=5+200)점이다.

  9. 위의 어떤 경우에도 해당하지 않을 때 점수는 가장 큰 숫자에 100을 더한다. 예를 들어, R1, R2, B4, B8, Y5 일 때 점수는 108(=8+100)점이다.

입력으로 카드 5장이 주어질 때, 카드 게임의 점수를 구하는 프로그램을 작성하시오. 두 가지 이상의 규칙을 적용할 수 있는 경우에는 가장 높은 점수가 카드 게임의 점수이다.

입력

첫첫째 줄부터 다섯째 줄까지 한 줄에 카드 하나씩 입력된다. 카드의 색깔과 숫자 사이에는 빈 칸이 하나 있다.

출력

한 줄에 카드의 점수를 출력한다.

코드

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

struct Card {
  char color[100];
  int num;
} card;

int comparison(struct Card card[]) {
  int color_cnt[4] = {0};
  int num_cnt[10] = {0};

  // card[i].num_cnt 에는 각 번호수마다 카드가 몇 개 있는지 구분가능
  // Ex) num_cnt[1] = 2 이면 1 카드가 2개 있는 거
  for (int i = 0; i < 5; i++) {
    int num = card[i].num;
    if (num >= 1 && num <= 9) {
      num_cnt[num]++;
    }

    if (strcmp(card[i].color, "R") == 0) {
      color_cnt[0]++;
    } else if (strcmp(card[i].color, "B") == 0) {
      color_cnt[1]++;
    } else if (strcmp(card[i].color, "Y") == 0) {
      color_cnt[2]++;
    } else if (strcmp(card[i].color, "G") == 0) {
      color_cnt[3]++;
    }
  }

  int max_num = 0;
  int score = 0;

  if (color_cnt[0] == 5 || color_cnt[1] == 5 || color_cnt[2] == 5 ||
      color_cnt[3] == 5) {
    for (int i = 1; i <= 9; i++) {
      // 1번 경우의 수
      if ((num_cnt[i] && num_cnt[i + 1] && num_cnt[i + 2] && num_cnt[i + 3] &&
           num_cnt[i + 4]) == 1) {
        if (score <= i + 904) {
          score = (i + 4) + 900;
          break;
        }
      } else {
        for (int k = 9; k >= 1; k--) {
          if (num_cnt[k] != 0) {
            if (score <= k + 600) {
              score = k + 600;
            }
          }
        }
      }
    }
  }

  for (int i = 1; i <= 9; i++) {
    // 2번 경우의 수
    if (num_cnt[i] == 4) {
      if (score <= i + 800) {
        score = i + 800;
      }
    }
    // 6번 경우의 수
    else if (num_cnt[i] == 3) {
      if (score <= i + 400) {
        score = i + 400;
      }
    }
    // 8번 경우의 수
    else if (num_cnt[i] == 2) {
      if (score <= i + 200) {
        score = i + 200;
      }
    }
  }

  for (int i = 0; i <= 5; i++) {
    // 5번 경우의 수
    if ((num_cnt[i] && num_cnt[i + 1] && num_cnt[i + 2] && num_cnt[i + 3] &&
         num_cnt[i + 4]) == 1) {
      if (score <= i + 504) {
        score = i + 504;
      }
    }
  }

  // 3번 경우의 수
  for (int i = 1; i <= 9; i++) {
    if (num_cnt[i] == 3) {
      for (int k = 1; k <= 9; k++) {
        if (num_cnt[k] == 2) {
          if (score <= i * 10 + k + 700) {
            score = i * 10 + k + 700;
          }
        }
      }
    }

    // 7번 경우의 수
    if (num_cnt[i] == 2) {
      for (int k = 1; k <= 9; k++) {
        if ((i != k) && (num_cnt[k] == 2)) {
          if (i > k) {
            if (score <= i * 10 + k + 300) {
              score = i * 10 + k + 300;
            }
          } else {
            if (score <= k * 10 + i + 300) {
              score = k * 10 + i + 300;
            }
          }
        }
      }
    }
  }

  for (int k = 9; k >= 1; k--) {
    if (num_cnt[k] != 0) {
      if (score <= k + 100) {
        score = k + 100;
      }
    }
  }

  printf("%d", score);
}

int main(void) {
  char color;
  int num;
  struct Card card[5];

  for (int i = 0; i < 5; i++) {
    scanf("%s %d", card[i].color, &card[i].num);
  }

  comparison(card);

  return 0;
}

문제를 풀면서 고민했던 점은 다음과 같다.
1. 카드를 색상과 카드수 2가지로 나누어야하는데 이후에 이것을 "연속된 수" 와 "같은 색상" 으로 어떻게 분류할 것 인가?

이 방법을 해결하기 위해 struct 구조체를 활용하고, 이후 배열로 나누는 방식을 사용함.
1) 우선 입력받는 5가지 경우를 Card struct로 color (char) 와 num (int)로 나눔
2) 이후 color_cnt 배열 -> 0 : R, 1 : B, 2:Y, 3:G
3) 이후 num_cnt 배열 -> 1 : 1번카드 개수, 2: 2번 카드 개수 ..... 9: 9번 카드 개수

2. 점수 계산하는 9가지 조건을 어떻게 효율적으로 정리할 수 있을까?

이총 4가지의 경우의수로 나눠서 풀었다.
1) 색이 5개가 같은 경우 -> 숫자가 연속 or 숫자 상관 X
2) 숫자가 동일한 경우 -> 4 / 3 & 2 / 3 / 2 & 2 / 2 개의 카드가 동일한 경우
3) 5장의 숫자가 연속한 경우
4) 이외의 경우 (9번 조건)

3. 두 가지 이상의 규칙을 적용할 수 있는 경우에는 어떻게 더 큰 카드의 점수를 적용할 것인가?

score 변수 지정 이후 if문을 활용해 새로운 score 의 점수가 더 큰 경우 대체하도록 설정

이런식으로 풀다보니 어떻게든 풀긴 풀었는데, 이상할정도로 복잡하게 문제를 푼 것 같아서 후에 다른사람들의 코드를 한번 보았다.

나같은 경우에는 color_cnt 배열과 num_cnt 배열을 사용해 R B Y G에 각각 몇개, 1 2 3 4 ... 9번 카드에 각 몇개 이런식으로 나누었는데, 더 쉽게 하려면

  1. (색 여부 관계 없이) 색이 겹치는게 1개, 2개, 3개, 4개인 경우를 배열로 분류

  2. 조건문 중간에 연속적인 숫자가 있는 경우를 if문으로 찾는 것이 아니라, 미리 앞에 조건문으로 만들어놓고 변수를 하나 지정해서 후에 점수계산에서 변수가 있는 경우, 없는 경우로 분류해두기

조금만 고민했으면 코드가 더 짧아질 수 있었다...ㅠㅠ

profile
I have prepared for My Life long 🌙

0개의 댓글