Programming/백준 (c++)

[백준] #8979번: 올림픽

마이구미포포 2022. 3. 21. 10:51

** 이 문제는 처음 틀린 코드와 맞은 코드 둘 다 리뷰를 해보겠다

문제

올림픽은 참가에 의의가 있기에 공식적으로는 국가간 순위를 정하지 않는다. 그러나, 많은 사람들이 자신의 국가가 얼마나 잘 하는지에 관심이 많기 때문에 비공식적으로는 국가간 순위를 정하고 있다. 두 나라가 각각 얻은 금, 은, 동메달 수가 주어지면, 보통 다음 규칙을 따라 어느 나라가 더 잘했는지 결정한다.

  1. 금메달 수가 더 많은 나라 
  2. 금메달 수가 같으면, 은메달 수가 더 많은 나라
  3. 금, 은메달 수가 모두 같으면, 동메달 수가 더 많은 나라 

각 국가는 1부터 N 사이의 정수로 표현된다. 한 국가의 등수는 (자신보다 더 잘한 나라 수) + 1로 정의된다. 만약 두 나라가 금, 은, 동메달 수가 모두 같다면 두 나라의 등수는 같다. 예를 들어, 1번 국가가 금메달 1개, 은메달 1개를 얻었고, 2번 국가와 3번 국가가 모두 은메달 1개를 얻었으며, 4번 국가는 메달을 얻지 못하였다면, 1번 국가가 1등, 2번 국가와 3번 국가가 공동 2등, 4번 국가가 4등이 된다. 이 경우 3등은 없다. 

각 국가의 금, 은, 동메달 정보를 입력받아서, 어느 국가가 몇 등을 했는지 알려주는 프로그램을 작성하시오. 

입력

입력의 첫 줄은 국가의 수 N(1 ≤ N ≤ 1,000)과 등수를 알고 싶은 국가 K(1 ≤ K ≤ N)가 빈칸을 사이에 두고 주어진다. 각 국가는 1부터 N 사이의 정수로 표현된다. 이후 N개의 각 줄에는 차례대로 각 국가를 나타내는 정수와 이 국가가 얻은 금, 은, 동메달의 수가 빈칸을 사이에 두고 주어진다. 전체 메달 수의 총합은 1,000,000 이하이다.

출력

출력은 단 한 줄이며, 입력받은 국가 K의 등수를 하나의 정수로 출력한다. 등수는 반드시 문제에서 정의된 방식을 따라야 한다. 

서브태스크

번호배점제한
1 8 예제 입력, 출력
2 12 N = 2
3 20 모든 국가의 은메달 및 동메달 획득 수는 0
4 25 N ≤ 500
5 35 추가적인 제약 조건은 없다.

예제 입력 1 

4 3
1 1 2 0
2 0 1 0
3 0 1 0
4 0 0 1

예제 출력 1 

2

예제 입력 2 

4 2
1 3 0 0
3 0 0 2
4 0 2 0
2 0 2 0

예제 출력 2 

2

 

첫번째 시도 (틀린 코드)

#include<iostream>

using namespace std;

char line[1000][4];

int main(void) {
	int n, k,grade=1;

	cin >> n >> k;

	for (int i = 0; i < n; i++) {
		cin >> line[i];
	}

	int m=0;
	for (int i = 0; i < n; i++) {
		if (line[i][0] == k + '0')
			m = i;
	}
		
	for (int i = 0; i < n; i++) {
		if (line[i][0] != k+'0') {

			if (line[i][1] > line[m][1]) { //금이 다른나라가 더 많을 때
				grade += 1;
			}

			if (line[i][1] == line[m][1]) { //금 똑같
				if (line[i][2] > line[m][2]) { //은이 다른나라가 더 많을 때
					grade += 1;
				}
				else if (line[i][2] == line[m][2]) { //은 똑같 
					if (line[i][3] > line[m][3])
						grade += 1;
				}
			}
		}
		else
			continue;
	}

	cout << grade;
		
}

char 형식을 통해 2차원 배열로 풀려고했다.

line[i][0] → 국가 번호 / line[i][1] → 금메달 / line[i][2] → 은메달 / line[i][3] → 동메달

 

(1) 국가의 수(n) 만큼 배열을 입력받아 line에 저장하고

(2) 지정한 국가 번호(k)의 인덱스(i)를 찾아 m에 저장

(3) 반복문을 통해 

     1. 금메달이 다른나라가 더 많을경우 grade+1
     2. 금메달 개수가 같을 경우 → 은메달 개수가 더 많을 경우 grade+1

                                        → 은메달 개수가 같을 경우 → 동메달 개수가 많을경우 grade+1

    로 나누어 지정한 국가의 grade를 출력

출력된 결과로 봤을때 구해야하는 grade (등수)에는 문제가 없다

문제는 국가번호/금/은/동을 문자열로 설정하여 공백으로 구분할 수 없다는 것이다.

 

이 문제를 해결하기위해 getline / cin.getline 모두 사용해보았으나 char 형식때문인지 오버로드로 인해 오류가 발생했다.

(이 부분은 좀 더 공부가 필요할듯 하다)

 

두번째 시도 (맞은 코드)

#include <iostream>

using namespace std;
 
int n, k;
int gold[1001];
int silver[1001];
int bronze[1001];
int grade = 1;
 
int main() {
 
    //입력
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        int index;
        cin >> index;
        cin >> gold[index] >> silver[index] >> bronze[index];
    }
 
    //1번 국가부터 N번 국가까지 K번 국가보다 더 잘한 국가일 경우 res++
    for (int i = 1; i <=n; i++) {
        if (gold[i] > gold[k]) {
            grade++;
        }
        else if (gold[i] == gold[k]) {
            if (silver[i] > silver[k]) {
                grade++;
            }
            else if (silver[i] == silver[k]) {
                if (bronze[i] > bronze[k]) {
                    grade++;
                }
            }
        }
    }
 
    //출력
    cout << grade;
}

 

국가 지정 번호 / 금 /은 /동을 한 배열에 저장하는 것이 아니라

국가 번호를 index로 하고 gold, silver, bronze 배열을 따로 만들어 입력/비교를 한다.

금,은,동 개수 비교하는 반복문 형태는 첫번째 코드와 동일하다.

 

cin 은 공백을 구분하여 입력받기 때문에 배열을 따로 설정하여 cin으로 받는다면 공백으로 번호,금,은,동을 구분할 수 있다.

첫번째 코드와 동일한 n,k, 금은동 개수를 입력했을때 결과가 같음을 알 수 있다.

 

 

**

첫번째 코드에서 

이 부분을

이렇게 바꾸어 풀었더니 두번째 코드처럼 공백으로 구분하여 결과를 출력할 수 있었다.

 

이중 반복문으로 백준에 다시 제출했을 때

아래부터 순서대로하여 이중반복문은 8점을 받았다. 더 효율적인 알고리즘이 있어서 8점인지, input 과정에서 문제가 있어서 8점인지는 좀 더 공부를 해봐야겠다....