[백준/C언어] 25206번 너의 평점은

EOH·2023년 3월 8일
0

백준

목록 보기
4/5
post-thumbnail

문제

인하대학교 컴퓨터공학과를 졸업하기 위해서는, 전공평점이 3.3 이상이거나 졸업고사를 통과해야 한다. 그런데 아뿔싸, 치훈이는 깜빡하고 졸업고사를 응시하지 않았다는 사실을 깨달았다!

치훈이의 전공평점을 계산해주는 프로그램을 작성해보자.

전공평점은 전공과목별 (학점 × 과목평점)의 합을 학점의 총합으로 나눈 값이다.

인하대학교 컴퓨터공학과의 등급에 따른 과목평점은 다음 표와 같다.

A+ 4.5
A0 4.0
B+ 3.5
B0 3.0
C+ 2.5
C0 2.0
D+ 1.5
D0 1.0
F 0.0
P/F 과목의 경우 등급이 P또는 F로 표시되는데, 등급이 P인 과목은 계산에서 제외해야 한다.

과연 치훈이는 무사히 졸업할 수 있을까?

입력

20줄에 걸쳐 치훈이가 수강한 전공과목의 과목명, 학점, 등급이 공백으로 구분되어 주어진다.

출력

치훈이의 전공평점을 출력한다.

정답과의 절대오차 또는 상대오차가
(10^{-4}) 이하이면 정답으로 인정한다.

제한

1 ≤ 과목명의 길이 ≤ 50
과목명은 알파벳 대소문자 또는 숫자로만 이루어져 있으며, 띄어쓰기 없이 주어진다. 입력으로 주어지는 모든 과목명은 서로 다르다.
학점은 1.0,2.0,3.0,4.0중 하나이다.
등급은 A+,A0,B+,B0,C+,C0,D+,D0,F,P중 하나이다.
적어도 한 과목은 등급이 P가 아님이 보장된다.


설명

문자를 숫자로 변환하는 것과, 어떤 자료구조에 담을지 생각하면서 풀어야하는 문제이다.

1️⃣ 성적을 점수로 파싱하는 방법

<string.h> 헤더에 있는 strstr함수를 사용하였다.
strstr함수는 문자열 안에 원하는 문자열이 있는지 찾는 함수로

char *strstr(const char *haystack, const char *needle);

이 형태로 사용하고 needle이 haystack안에 있으면 그 포인터를 없으면 NULL을 반환한다.

🌟 이 때 소수를 어떤 자료형으로 받는게 좋을까?
float형과 double형의 차이에 대해 고민해 보았다.
float형과 double형의 차이는 사용하는 비트갯수에서 오는 정밀도차이이다. 간단히 말하면 double형이 약 2배이상의 비트를 사용하고 정밀도도 더 높다.
소수를 표현하는 방법을 따로 정리해두어 아래 링크로 들어가면 된다.
<정수와 실수의 표현 방법>

2️⃣ 연결 리스트

scanf로 받으면서 바로 변수에 담아 더해버리면서 처리하는 방법도 있으나, 리스트에 담으면 받은 데이터를 저장해놓고 처리할 수 있을 것 같아 리스트를 선택했다.
이차원 배열을 이용해서 저장할 수 도 있으나 구조체를 선언하는 것이 더 직관적이어서 리스트를 선택했다.

typedef struct s_node{
   struct s_node *next;
   double n_credit;
   double n_grade;
}t_node;

구조체는 위와 같이 선언하였다. 과목명은 사용하지 않을거라 저장하지 않았고, 학점과 과목평점을 double형으로 가지고 있는 노드를 만들었다.

main함수에서 list의 head를 선언, head의 뒤 부터 이어붙이는 방식으로 list에 데이터를 저장했다.

3️⃣ 코드설명

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

typedef struct s_node{
    struct s_node *next;
    double n_credit;
    double n_grade;
}t_node;

t_node *make_lst(void)
{
    t_node *new;

    new = (t_node *)malloc(sizeof(t_node));
    if (!new)
        return (0);
    new->next = NULL;

    return (new);
}
// 새 node를 만드는 함수. 
//head node를 만들거나 list에 이어붙일 새 노드를 만드는데 쓰일 것이다. 

double trans_credit(char *credit)
{
    double f_credit;

    if (strstr(credit, "A+") != NULL)
        f_credit = 4.5;
    else if (strstr(credit, "A0") != NULL)
        f_credit = 4.0;
    else if (strstr(credit, "B+") != NULL)
        f_credit = 3.5;
    else if (strstr(credit, "B0") != NULL)
        f_credit = 3.0;
    else if (strstr(credit, "C+") != NULL)
        f_credit = 2.5;
    else if (strstr(credit, "C0") != NULL)
        f_credit = 2.0;
    else if (strstr(credit, "D+") != NULL)
        f_credit = 1.5;
    else if (strstr(credit, "D0") != NULL)
        f_credit = 1.0;
    else if (strstr(credit, "F") != NULL)
        f_credit = 0.0;
    else
        f_credit = -1.0;
    return (f_credit);
}
//학점 변환하는 함수, 학점이 P이면 넘어갈 수 있게 -1.0으로 flag를 준 것이다. 

void lst_addbck(t_node **lst, double credit, double grade)
{
    t_node *new;
    t_node *temp;

    temp = *lst;

    if (grade == -1)
        return ;
    new = make_lst();
    
    while (temp->next != NULL)
        temp = temp->next;
    new->n_credit = credit;
    new->n_grade = grade;
    temp->next = new;
}
// list의 가장 마지막에 이어붙이는 함수. 
//원본 리스트는 그 주소값에 접근해서 값을 바꾸어주어야되기 때문에 이중포인터로 접근해야한다. 

int main(void)
{
    char subject[50];
    char c_grade[2];
    double credit, grade;
    t_node *lst;
    t_node *temp;
    double x, y;

    x = 0.0;
    y = 0.0;

    lst = make_lst();

    for(int i = 0; i < 20; i++)
    {
        scanf("%s", subject);
        scanf("%lf", &credit);
        scanf("%s", c_grade);
        grade = trans_credit(c_grade);
        lst_addbck(&lst, credit, grade);
    }

    temp = lst->next; 
    //head다음 실제로 데이터가 담긴 부분부터 조회하기 위함
    
    while (temp != NULL)
    {
        x += (temp->n_credit) * (temp->n_grade);
        y += temp->n_credit;
        temp = temp->next;
    }

    if (x == 0 || y == 0)
    {
        printf("0.000000");
        return (0);
    }

    printf("%f\n", x/y);

    return (0);
}

p.s

0/0을 하면 nan이 나와서 따로 처리했다. 왜 그런지 찾아보자
y의 값을 n_grade의 합계로 잘못 설정해서 처음에 틀렸었다. 숫자가 많을수록 차분하게 문제를 읽어보자

profile
에-오

0개의 댓글