- 문제
인하대학교 컴퓨터공학과를 졸업하기 위해서는, 전공평점이 3.3 이상이거나 졸업고사를 통과해야 한다. 그런데 아뿔싸, 치훈이는 깜빡하고 졸업고사를 응시하지 않았다는 사실을 깨달았다!
치훈이의 전공평점을 계산해주는 프로그램을 작성해보자.
전공평점은 전공과목별 (학점 × 과목평점)의 합을 학점의 총합으로 나눈 값이다.
인하대학교 컴퓨터공학과의 등급에 따른 과목평점은 다음 표와 같다.
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가 아님이 보장된다.
#include<iostream>
#include<string>
using namespace std;
double totalCredit;;
double transferredGrade[20];
double answer;
void fast_io() {
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
}
class Major {
public:
string subject;
double credit;
string grade;
};
void input(Major* m) {
for (int i = 0; i < 20; i++) {
cin >> m[i].subject >> m[i].credit >> m[i].grade;
if (m[i].grade.size() > 1) {
if (m[i].grade[0] == 'A') {
transferredGrade[i] = 4.0;
}
else if (m[i].grade[0] == 'B') {
transferredGrade[i] = 3.0;
}
else if (m[i].grade[0] == 'C') {
transferredGrade[i] = 2.0;
}
else if (m[i].grade[0] == 'D') {
transferredGrade[i] = 1.0;
}
else {
}
if (m[i].grade[1] == '+') {
transferredGrade[i] += 0.5;
}
else {
}
totalCredit += m[i].credit;
}
else {
if (m[i].grade[0] == 'F') {
transferredGrade[i] = 0.0;
totalCredit += m[i].credit;
}
else {
transferredGrade[i] = -1.0;
}
}
}
}
int main() {
fast_io();
Major majors[20];
input(majors);
double totalSum = 0.0;
for (int i = 0; i < 20; i++) {
if (transferredGrade[i] == -1.0) {
continue;
}
double score = majors[i].credit * transferredGrade[i];
totalSum += score;
}
answer = totalSum / totalCredit;
cout << answer;
return 0;
}
입력의 크기가 20으로 제한되어 있어 시간 초과 관련해서는 딱히 신경쓸게 없었다. 과목명, 학점, 성적을 입력받기 위해 Major이라는 Class를 설계하였지만 과목 명은 딱히 문제에서 사용되지 않기 때문에 Class 설계까지는 굳이 할 필요는 없어보이긴 한다.
문제에서 성적을 학점으로 바꾸는 것과 Pass 과목은 성적 산출 시 포함시키지 않는 것이 핵심이다. 성적의 입력이 2글자로 제한되어있기 때문에 F와 P를 제외한 성적은 첫번째 글자로 1,2,3,4를 정한 후 뒤에 + 유무에 따라 0.5점을 더해주는 방식을 사용하여 분기를 최소화 시키려고 노력했다.
Pass인 과목 부분을 합산하지 않기 위해 -1로 두어 나중에 구분할 수 있도록 하였다.
#include <iostream>
int main() {
char S[51], G[3];
int i = 0;
double m = 0, s = 0, g, c;
for (; i < 20; i++) {
std::cin >> S >> g >> G;
if (G[0] == 'P') continue;
c = 'E' - G[0];
if (c < 0) c = 0;
else if (G[1] == '+') c += 0.5;
s += g; m += g * c;
}
std::cout << m / s;
}
학점을 숫자로 변환하는 과정에서 'E'-입력받은 첫번째 알파벳으로 학점을 바꾸는 부분이 분기를 하지 않아도 되어 매우 효율적으로 보인다. (F가 나오면 음수를 캐치에서 0으로 변환)
공감하며 읽었습니다. 좋은 글 감사드립니다.