상세 컨텐츠

본문 제목

백준#1946 - 신입 사원

C#/알고리즘

by McRobbin 2020. 4. 12. 15:27

본문

https://www.acmicpc.net/problem/1946

 

1946번: 신입 사원

첫째 줄에는 테스트 케이스의 개수 T(1 ≤ T ≤ 20)가 주어진다. 각 테스트 케이스의 첫째 줄에 지원자의 숫자 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N개 줄에는 각각의 지원자의 서류심사 성적, 면접 성적의 순위가 공백을 사이에 두고 한 줄에 주어진다. 두 성적 순위는 모두 1위부터 N위까지 동석차 없이 결정된다고 가정한다.

www.acmicpc.net

그리디 알고리즘으로 분류된 1946 신입사원 문제 입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace _1946
{
    class Program
    {
        //Program 클래스 안에서만 사용할 지원자 클래스 정의.
        class Applicant : IComparable
        {
            //첫번째 시험의 등수, 두번째 시험의 등수를 멤버 변수로 가짐.
            public int first;
            public int second;
 
            public Applicant(int first, int second)
            {
                this.first = first;
                this.second = second;
            }
 
            //첫번째 시험을 기준으로 정렬.
            public int CompareTo(object obj)
            {
                return first.CompareTo((obj as Applicant).first);
            }
        }
 
        static void Main(string[] args)
        {
            int examCount = int.Parse(Console.ReadLine());
 
            //시험 횟수만큼 반복.
            for (int j = 0; j < examCount; j++)
            {
                //지원자 점수를 저장할 리스트.
                var AppList = new List<Applicant>();
 
                //지원자 수
                int appCount = int.Parse(Console.ReadLine());
 
                for(int i = 0; i < appCount; i++)
                {
                    //지원자 숫자만큼 입력 받음.
                    string[] strAppScore = Console.ReadLine().Split(' ');
                    AppList.Add(new Applicant(int.Parse(strAppScore[0]), int.Parse(strAppScore[1])));
 
                }
 
                //지원자가 1명일 때 무조건 합격.
                if (appCount == 1)
                {
                    Console.WriteLine(1);
                    continue;
                }
 
                //지원자들을 첫번째 시험점수 기준으로 정렬
                AppList.Sort();
 
                //시험을 가장 잘본 지원자와 실패한 숫자를 초기화.
                Applicant bestApp = AppList[0];
                int failAppCount = 0;
 
                for(int i = 1; i < appCount; i++)
                {
                    //가장 잘본 사람의 실기 등수 보다 확인하는 사람의 실기 등수가 안좋을 때;
                    if (AppList[i].second > bestApp.second)
                        failAppCount++;
 
                    //실기 등수가 높을 때.
                    else
                        bestApp = AppList[i];
                }
 
                Console.WriteLine(AppList.Count - failAppCount);
            }
        }
    }
}
 
 

 

문제 설명.

각 지원자는 두번의 시험(필기 시험, 면접)을 치룹니다.

이를 각각 first, second로 칭하겠습니다.

문제의 설명은 한 지원자 A의 두가지 시험 등수가 어떤 지원자 B의 두가지 시험 등수 보다 안좋다면 A는 반드시

탈락해야 합니다. 예를 들겠습니다.

 

ex) 1번의 공채가 있고 4명의 지원자가 있습니다. 각각의 등수는 다음과 같습니다.

지원자    필기     면접

1 :          3         2

2 :          2         4

3 :          1         3

4 :          4         1

이와 같이 있을 때 1번 지원자는 2번 지원자와 비교했을 때 필기는 등수가 떨어지지만 면접은 잘봤습니다. 그렇다면 1번

지원자는 탈락하지 않습니다. 하지만 3번 지원자와 다시 비교해봐야 합니다.

1번 지원자는 3번 지원자보다 필기가 떨어지지만 면접을 잘봤습니다. 탈락하지 않습니다.

1번 지원자는 4번 지원자보다 필기를 잘봤습니다. 탈락하지 않습니다.

==> 1번 지원자는 탈락하지 않습니다.

 

2번 지원자를 보겠습니다. 1번 지원자 보다 필기를 잘봤습니다. 다음 3번과 비교해 보겠습니다.

3번 지원자 보다 필기, 면접 모두 등수가 떨어집니다. 그러므로 2번 참가자는 탈락해야 합니다.

==> 2번 지원자는 3번 지원자 보다 필기, 면접 모두 못봤으므로 탈락.

 

이와 같이 한 참가자에 대해 다른 모든 참가자와 각 점수를 모두 비교해봐야 알 수 있습니다.

하지만 이는 O(N^2) 시간이 걸리며 10만의 참가자가 있을 경우 시간 초과가 발생할 수 있습니다.

 

본격적 문제 해결.

지원자(Applicant)라는 클래스를 정의했습니다. 필기 시험 점수 first와 실기 시험 점수 second를 가지고 있고,

제가 원하는 기준으로 정렬하기 위해 IComaparable의 CompareTo를 정의 했습니다.

CompareTo 함수는 필기 시험을 기준으로 정렬 했으며 면접 점수를 기준으로 해도 관계 없습니다.

 

해결 방법을 보겠습니다. 위의 예시를 그대로 가져오겠습니다.

ex)

지원자    필기     면접

1 :          3         2

2 :          2         4

3 :          1         3

4 :          4         1

이를 필기 시험에 대해 오름차순 소트하면 결과는

지원자    필기     면접

3 :          1         3

2 :          2         4

1 :          3         2

4 :          4         1

이와 같이 나오게 됩니다. 3번 지원자는 필기에서 1등을 했으므로 무조건 합격이며 2번 지원자를 보겠습니다.

2번 지원자는 3번 지원자보다 필기 시험을 못봤음이 명백합니다. 그러므로 위의 참가자 중 면접 등수가

본인보다 높은 지원자가 있는지 확인하면 됩니다. 3번 지원자는 2번 보다 면접을 잘 봤기에 2번은

탈락해야 합니다.

 

다음으로 1번 참가자를 보기 전에 위의 참가자 중 면접을 가장 잘 본 지원자를 업데이트 해야 합니다.

1번 참가자는 3, 2번 참가자와 면접 점수를 모두 비교해 봐야 합니다. 필기는 못봤음이 분명하구요.

위의 지원자 중 면접을 가장 잘본 사람을 가지고 있다면 그 지원자만 비교하면 될 것입니다.

 

2번이 3번과 비교할 때 2번이 탈락 했다면 면접 또한 낮은 것이므로 탈락자 수만 하나 올리고 업데이트 하지 않습니다.

2번의 면접 등수가 1번보다 높았다면 탈락하지 않으며 그 면접 점수를 여태 본 지원자 중 가장 면접 점수가 높았던 곳에 업데이트해 가지고 있습니다. 그럼 다음에 보는 1번 지원자는 3, 2번 지원자 보다 필기 등수가 낮으며 면접을 가장 잘 본

2번 사람과만 비교하면 될 것입니다. 이것을 마지막 참가자 까지 반복하면 되겠습니다.

'C# > 알고리즘' 카테고리의 다른 글

백준#2529 - 부등호  (0) 2020.04.12
백준#1049 - 기타줄  (0) 2020.04.12
백준#1120 - 문자열  (0) 2020.04.11
백준#1541 - 잃어버린 괄호  (0) 2020.04.11
백준#2875 - 대회 or 인턴  (0) 2020.04.11

관련글 더보기