Altiora Petamus

신입사원 본문

1day-1algorithm

신입사원

Haril Song 2021. 2. 24. 16:07

 

백준 1946번

 

문제

언제나 최고만을 지향하는 굴지의 대기업 진영 주식회사가 신규 사원 채용을 실시한다. 인재 선발 시험은 1차 서류심사와 2차 면접시험으로 이루어진다. 최고만을 지향한다는 기업의 이념에 따라 그들은 최고의 인재들만을 사원으로 선발하고 싶어 한다.

그래서 진영 주식회사는, 다른 모든 지원자와 비교했을 때 서류심사 성적과 면접시험 성적 중 적어도 하나가 다른 지원자보다 떨어지지 않는 자만 선발한다는 원칙을 세웠다. 즉, 어떤 지원자 A의 성적이 다른 어떤 지원자 B의 성적에 비해 서류 심사 결과와 면접 성적이 모두 떨어진다면 A는 결코 선발되지 않는다.

이러한 조건을 만족시키면서, 진영 주식회사가 이번 신규 사원 채용에서 선발할 수 있는 신입사원의 최대 인원수를 구하는 프로그램을 작성하시오.

 

입력

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

 

출력

각 테스트 케이스에 대해서 진영 주식회사가 선발할 수 있는 신입사원의 최대 인원수를 한 줄에 하나씩 출력한다.

 

예제 입력

예제 출력

2
5
3 2
1 4
4 1
2 3
5 5
7
3 6
7 3
4 2
1 4
5 7
2 5
6 1
4
3

 

풀이법

  1. emp1에 모든 지원자의 순위를 저장한다.
  1. emp1을 서류 점수 순위를 기준으로 정렬한 후 1위보다 면접 순위가 높은 사람을 1차 합격자로 가정하여 emp2에 저장한다.
  1. emp2(1차 합격자들)을 면접 순위를 기준으로 정렬한 후 1위보다 서류 순위가 높은 사람을 최종 합격자로 한다.
  1. 최종 합격자의 숫자를 cnt에 저장 후 반복문이 종료되는 시점에 pass_cnt에 저장한다.
  1. 다음 테스트케이스가 실행될 때 emp1, emp2, cnt를 모두 초기화한다.
  1. 테스트케이스를 검증하는 반복문이 종료된 후 pass_cnt를 반복문을 통해 한 줄씩 출력한다.

 

어떻게 풀어야하는지 고민하던 과정.. 생각을 거듭할수록 점점 옳게 되고 있다.

 

첫번째 시도

from operator import itemgetter # 다차원배열의 정렬을 위해 사용

T = int(input()) # 테스트의 갯수

pass_cnt = []
for _ in range(T):
    emp1 = []
    emp2 = []
    cnt = 0 # 최종합격자의 수
    N = int(input()) # 지원자의 숫자
    
    # [서류심사 순위, 면접 순위]
    for _ in range(N):
        emp1.append(list(map(int, input().split())))
		
		# 서류 순위로 정렬
    emp1.sort(key=itemgetter(0))
    # print(emp1)

    for i in emp1:
       if i[1] <= emp1[0][1]: # 자기 자신은 통과해야한다
           emp2.append(i) # 1차 합격자

		# 면접 순위로 정렬
    emp2.sort(key=itemgetter(1))
    # print(emp2)

    for i in emp2:
        if i[0] <= emp2[0][0]:
            cnt += 1
    
    pass_cnt.append(cnt) # 최종 합격자의 인원수를 저장
    
for i in pass_cnt:
    print(i)

기본 예제 및 따로 테스트를 위해 작성해둔 예제를 전부 통과했지만 막상 제출해보니

예상했던 시간초과도 아니고

오답이라는 결과가 나왔다. 뭔가 예외처리를 해야하는 패턴이 있는걸까.

 

무슨 점수든 1위는 반드시 존재해야하니 최소 1명은 합격해야할 것이고 전원 합격의 경우도 예상한대로 값이 나온다.

 

이렇게 예제를 모두 통과했는데 오답이라는 결과가 나오면 어떤 구간에서 문제가 있는지 도통 알수가 없어서 답답하다 ㅠ 도대체 어디를 고쳐야할지...

 

오답도 오답이지만 코드 자체의 시간복잡도도 있고 맞든 틀리든 코드를 리팩토링 해보기로 했다.

 

리팩토링 및 풀이법 V2

import sys

T = int(input()) # 테스트의 갯수

for _ in range(T):

    N = int(input()) # 지원자의 숫자

    emp1 = sorted([list(map(int, sys.stdin.readline().strip().split()))
					for _ in range(N)], key = lambda x: x[0])

		cnt = 1 # 최종합격자의 인원수, 한명도 통과하지 못하는 경우는 없다
    min = emp1[0][1] # 서류 점수 1위의 면접 순위를 저장한 후 비교

    for i in range(1, N):
        if emp1[i][1] < min:
            min = emp1[i][1] # 지금까지 만난 가장 좋은 면접 순위를 저장
            cnt += 1
    
    print(cnt)
  1. 지원자의 숫자가 최대 100,000명까지 들어오기 때문에 최대한 속도를 빠르게 하기 위해서 input 대신 sys를 사용하도록 했다.
  1. 리스트 자체를 변경하는 sort() 대신 리스트를 반환해주는 sorted() 내장함수를 사용해서 입력, 내장된 반복문, itemgetter로 처리했던 첫번째 정렬까지 한 번에 작성했다. 앞선 코드에서 itemgetter로 정렬하는 방식은 직관적이여서 좋았지만 성능을 잘 모르기도 해서 회의일정 문제에서 알아두었던 lambda를 활용해보았다. 참고로 회의일정 문제에서는 두 번의 연속적인 정렬을 수행하기 위해 키값을 튜플로 주어서 해결했었다.
  1. 처음 작성했던 코드에서 오답처리된 이유인데, 면접 순위로 정렬한 후 서류 점수로 비교할 때 더 좋은 순위가 나오면 그 순위로 다시 비교를 해야하는데 이 부분을 고려하지 못해서 오답처리가 된 것이였다. 새로 작성한 코드에서는 면접 순위로 재정렬하지 않고, 직접 비교하여 불필요한 정렬과정을 없앴다.
  1. 또 한 번에 출력하지 않으면 정답처리가 안되는 줄 알았는데 아니였다.. 그래서 마지막에 배열 pass_cnt에 정답을 넣고 출력하는 과정을 삭제하고 테스트케이스 반복문 중간에 출력코드를 삽입했다.

 

처음 작성한 코드가 오답처리된 이유
...
6 1
5 3
2 4
4 5
...
 면접 점수를 기준으로 정렬된 1차 합격자들의 서류 점수를 비교할 경우 6을 먼저 비교하게 되는데
 중간 부분을 보면 알 수 있듯이 [4, 5] 는 [2, 4] 지원자로 인해 탈락해야하는데
 4 < 6 은 True 이므로 2를 비교하는 순위로 재설정하지 않을 경우 합격하게 된다.

 

결과 확인

가장 높은 순위를 저장하고 다시 비교하는 과정을 추가해준 코드로 제출해본 결과, '맞았습니다' 라는 문구를 확인할 수 있었다. 또한 장황했던 처음 작성코드에 관련 로직만 추가해서 제출해봤는데 약 2배 가까이 느렸지만 시간초과가 나지 않고 통과했다.

 

...
#처음 제출 코드에서 수정
emp2.sort(key=itemgetter(1))
    # print(emp2)

		min = emp2[0][0]
    for i in emp2:
        if i[0] < min:
						min = i[0]
            cnt += 1
    
    pass_cnt.append(cnt) # 최종 합격자의 인원수를 저장
...

 

의외로 처음 작성한 코드에서도 시간초과가 발생하지 않았다.

 

 

 

Reference

'1day-1algorithm' 카테고리의 다른 글

캠핑  (0) 2021.03.01
단어수학  (0) 2021.02.25
로프  (0) 2021.02.23
동전 0  (0) 2021.02.20
ATM  (0) 2021.02.19