[백준] 19583. 싸이버개강총회

톰아저씨·2021년 10월 15일
0

BOJ

목록 보기
2/4
import sys
input = sys.stdin.readline


times = list(input().split())
S = int(times[0][:2]+times[0][3:])
E = int(times[1][:2]+times[1][3:])
Q = int(times[2][:2]+times[2][3:])
student = dict()
cnt = 0

while True:
    log = input()
    if len(log) < 3:
        break
    time, chat = log.split()
    time = int(time[:2]+time[3:])
    if time <= S:
        student[chat] = 1
    elif E<=time<=Q:
        if student.get(chat) and student[chat] == 1:
            cnt +=1
            student[chat] = 0

print(cnt)

매일매일 알고리즘 도전중, 오늘은 SSAFY 마지막 알고리즘 수업날이어서 그런지 꽤 싱숭생숭한 기분이었다. 그래도 매일매일 도전은 멈추면 안되지.

문자열, 딕셔너리

처음 문제를 보고 든 생각이, '입력을 어떻게 받으란 거야?' 였다. 보통 N이건 M이건 입력의 한계선을 주는 여타 문제들하곤 다르게 달랑 채팅로그만 주고 해보세요 하는 문제다 보니 (아마 그래서 실버 1티어에 들어가 있는 게 아닐까 싶다) 어떻게 해야 끝까지 다 인풋을 받아서 처리할지를 고민하게 되는 문제였다.

로직 생각하기

다행스럽게도, 00:00부터 시작해 23:59에서 끝난다는 점 때문에 시간순으로 정렬하는 건 어렵지 않았다. 총 3단계로 생각했다.

  1. 시간을 잘 나눠서 저장하기 : 채팅이 입력된 시간을 문자열 파싱으로 잘 나눠, 온전한 숫자로 인식할 수 있게 한다. (23:59는 2359로, 16:54는 1654로.)
    • 지금 와서 생각해보니, split()을 사용해서 더 깔끔하게 나눌 수 있다는 사실이 생각난다. 무식하게 슬라이싱으로 처리 안 해도 됐을 것 같다.
  2. 딕셔너리 사용하기 : 유저명을 키로, 시간 기준을 세워 해당 값이 밸류로 들어가는 딕셔너리를 생각했다. 기준치가 되는 시간 내에 채팅이 있었다면 +1, 최종값이 2라면 출석인정을 하는 식이었다.
  3. 인풋 받기 : 그래서 어떻게 인풋을 받을 것이냐.. 하는 생각. 이 부분은 구글링을 좀 해봤다. 마지막에 엔터가 하나 더 들어가기 때문에, 만약 입력값이 특정 값 이하라면 while문을 break해서 무한루프를 나가는 로직을 생각했다.

구현 자체는 난이도가 그렇게 높지 않았다. 부분마다 코멘트를 달아봐야지.

인풋 받기

import sys
input = sys.stdin.readline


times = list(input().split())
S = int(times[0][:2]+times[0][3:])
E = int(times[1][:2]+times[1][3:])
Q = int(times[2][:2]+times[2][3:])
student = dict()
cnt = 0
  1. input 명령어를 sys.stdin.readline으로 대체한다. (안 좋은 습관이라고는 하는데, 자연스럽게 저렇게 치게 되더라.)

  2. times 명령어는 개강총회의 시간들이다. 총 3개인데, 가공을 좀 할 거라서 일단 list로 받았다. 0번은 S, 1번은 E, 2번은 Q다.

  3. 문자열을 가공한다. 중간에 : 기호가 있으므로, 슬라이싱을 통해 합쳐주고 int로 만들어 대소비교가 가능하게 만든다.

  4. student 변수에는 dict를 사용한다 (빈 딕셔너리지만, 곧 인풋이 들어갈 것이다.)

  5. cnt변수는 최종 값이 될 변수다.

분류 돌리기

while True:
    log = input()
    if len(log) < 3:
        break
    time, chat = log.split()
    time = int(time[:2]+time[3:])
    if time <= S:
        student[chat] = 1
    elif E<=time<=Q:
        if student.get(chat) and student[chat] == 1:
            cnt +=1
            student[chat] = 0

print(cnt)
  1. while True : 무한루프를 돈다. 입력값이 어떻게 끝날 지 모르니 우선 선언해 둔다.

    • 처음 풀 때는 이걸 고려하지 않고 cnt를 10만 이하로 했었는데, 그랬더니 계속 계속 입력을 받아야 하더라.
  2. 입력받은 한 줄은 log변수에 저장한다. 이걸 기준으로 루프가 계속 돌지, 아니면 터질지를 생각한다.

  3. time, chat 변수는 스페이스로 쪼개지는 인풋들을 기록한다. 각기 시간과 채팅 입력자를 의미한다.

  4. if time<=S 조건문을 통해 입장 시간을 잰다. 문제의 조건에 개강총회 시작 이전에 들어와있어야 출석 인정되므로, S 이하라고 지정한다. 만약 이 조건문에 부합한다면 딕셔너리에 값이 추가된다. (1)

  5. elif E<=time<=Q 조건문을 통해 퇴장 시간을 잰다. 총회에 출석한 걸로 인정되는 사람은 개강총회 시작 이전에 들어와있고, 종료 이후에 채팅을 남긴 사람들이다. 애초에 입장 자체를 못 하면 재는 의미가 없어, get선언으로 딕셔너리에 값이 존재하는지를 본 다음 값이 있으면 출석으로 인정 (cnt+1) 하고 채팅을 0으로 되돌린다.

    • 이걸 0으로 안 되돌리면 여러 번 채팅을 친 사람이 있어 오답이 발생한다. (아...)
  6. 루프가 깨지면 (입력이 다 받아졌으면) cnt를 인쇄하고 답을 맞춘다.

TIL

  1. 디버깅 : 로직 자체는 깔끔하게 나왔다고 생각했는데, 예상하지 못한 곳에서 버그가 터지는 바람에 적잖이 당황했다. 역시 손으로 직접 그려보고 써보는 게 최고인 것 같다.
  2. 딕셔너리 : 아직 썩 익숙하지 않아서 get선언을 구글링해 문서를 보고 나서야 적용할 수 있었다. 왠지 알고리즘이 어려워질수록 딕셔너리를 계속 쓰게 될 것 같다.
  3. 나는 아직도 초등학생 레벨이라는 점. 더 분발하자. 스터디원들 보기 부끄럽지 않게!
profile
초등학생 수준 개발자

0개의 댓글