Minjeong / 11월 2주차 / 9문제 #85
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
주 목표 문제 수: 3개
백준 #3665. 최종 순위: 위상정렬 / 골드1
정리한 링크: (바로가기)
🚩플로우 (선택)
t)를 받아 반복한다.n)와 작년 순위 정보(info)를 받아서 초기 그래프(graph)와 진입차수(indegree) 리스트를 초기화한다.graph[i]에는i번 팀보다 뒤에 있는 팀들의 리스트를 추가하고, 각 팀의 진입차수를 기록한다.m)를 받아 각 쌍마다 간선 방향을 바꾼다.b가a보다 뒤에 있는 경우에는 순위가 변경된 경우이므로, 기존 간선을 제거하고 새 순서로 간선 추가한다.topology_sort함수에서 위상정렬을 수행하여 올해의 순위를 결정한다.queue에 넣어가며 순서대로 처리하고queue가 빌 때가지 반복한다.ranking에 추가한다.IMPOSSIBLE을 출력한다.ranking리스트를 문자열로 바꾸어 출력한다.🚩제출한 코드
💡TIL
백준 #2644. 촌수계산: DFSBFS / 실버2
정리한 링크: (바로가기)
🚩플로우 (선택)
n, 촌수를 계산할 두 사람의 번호a와b를 입력받고, 부모-자식 관계의 개수m줄만큼x,y를 입력받아graph를 연결한다.visited리스트를 초기화한다.result는 -1로 설정하여 촌수를 찾지 못한 경우를 대비한다.a로 지정하고 탐색을 시작한다.level+1을 넘겨줘서 촌수를 계산한다.b라면,result변수에level을 업데이트하고 재귀 호출을 종료한다.result를 출력한다.n, 촌수를 계산할 두 사람의 번호a와b를 입력받고, 부모-자식 관계의 개수m줄만큼x,y를 입력받아graph를 연결한다.visited리스트를 초기화하고, 시작 노드a부터 탐색할 수 있도록 BFS 큐를 설정한다.dist값을(a, 0)형태로 추가한다.dist를 꺼내고, 현재 노드가 목적지b와 같은지 확인한다.b일 경우, 최단 거리dist를 반환하여 촌수 계산을 완료한다.b가 아닐 경우, 해당 노드와 연결된 모든 이웃 노드를 확인한다.(neighbor, dist + 1)로 추가하여 다음 탐색 대기로 설정한다.b에 도달하지 못한 경우, 두 사람이 연결되지 않았음을 의미하므로 -1을 반환한다.🚩제출한 코드
DFS
BFS
💡TIL
level > 3일 때 종료되도록 불필요한 조건을 넣어 초반에 틀렸었다. 앞으로는 종료 조건을 설정할 때 문제 내용을 다시 확인하자.level을 매개변수로 넘기지 않고 global 키워드를 이용해 변수를 더하고 감소시키는 방식으로 관리했다가 원하는 촌수가 누락되는 문제를 겪었다. 깊이를 구할 때는 전역 변수보다는 매개변수로 전달하는 방식이 더 안정적이라는 걸 깨달았다.백준 #7562. 나이트의 이동: DFSBFS / 실버1
정리한 링크: (바로가기)
🚩플로우 (선택)
directions리스트에 정의한다.t를 입력받아 아래 과정들을 수행한다.t만큼 반복한다.l, 현재 위치(cur_x, cur_y)와 이동하려는 목표 위치(fin_x,fin_y)를 입력받는다.l의 크기만큼chess_map을 만든다.chess_map의 1칸은 -1로 설정한다. 이 칸을 이동할 때마다 이전 칸의 값을 더하여 이동하는 횟수를 저장하도록 한다. 처음에는 아무곳에도 이동하지 않았으므로 -1로 설정한다.queue에 시작 위치를 추가하고chess_map에 시작 위치 값을 0으로 설정한다.queue가 빌 때까지 반복하며, 현재 위치에서 모든 가능한 방향으로 이동을 시도한다.chess_map의 범위를 벗어나지 않는지 확인하고 방문하지 않은 위치의 경우 이동 횟수를 갱신하고queue에 추가한다.fin_x,fin_y)에 도달하면 탐색을 중지하고 이동 횟수를 반환한다.🚩제출한 코드
💡TIL
최단 이동 경로를 구하는 문제는 BFS가 짱이다.
매번 1칸씩 이동하는 문제를 풀다가 나이트 방향대로 이동하는 문제를 푸니까 새로웠다.
(0, 0), (-1, -2), (1, -2), (-2, -1), (2, -1), (-1, 2), (1, 2), (-2, 1), (2, 1)마지막 예제인 현재 위치와 목표 위치가 같은 경우에 자꾸 None이 나왔다. 그 이유는 코드에 방문하지 않았을 경우에, 목표지점을 발견했다면 반환하도록 코드를 짰기 때문이었다. 그래서 현재 자신의 위치를 이미 방문했다고 판단하여 아예 탐색을 하지 않고, 나머지 위치를 모두 탐색하였지만 목표지점이 발견되지 않아 반환할 게 없었던 것이다. 즉, 목표지점인지 파악하는 조건문을 방문하지 않았는지의 조건 안에다가 넣으면 안 되고, 1) 방문하지 않았는지 판단하는 조건 2) 목표지점인지 도달했는지 파악하는 조건을 각각 배치해야 한다.
백준 #18352. 특정 거리의 도시 찾기: DFSBFS / 실버2
정리한 링크: (바로가기)
🚩플로우 (선택)
n, 도로의 개수m, 최단거리k, 출발도시 번호x를 입력받고, 방문여부를 판단하는visited리스트와 그래프로 표현할graph리스트, 정답을 저장할answer리스트를 초기화한다. 이때visited리스트는 방문 여부를 판단할 뿐만 아니라 거리를 저장하는 역할로써 사용한다.graph를 단방향으로 연결한다.x부터 BFS 탐색을 시작한다.k인 모든 도시 번호를 저장할 리스트answer를 초기화한다.queue에 시작 위치를 추가하고 visited에 시작 위치 값을 0으로 설정한다.queue가 빌 때까지 아래 과정을 반복한다.queue에 추가하고, 방문 표시를 한다. 이때 방문 표시는 현재 노드의 거리에 +1을 해준다.visited[connected_node])가 최단거리 k와 같다면answer리스트에 추가한다.answer리스트를 반환한다.answer리스트가 존재하지 않는 경우는 최단 거리k인 도시가 하나도 존재하지 않는 경우이기 때문에 -1을 출력하고, 존재하는 경우에는 오름차순으로 정렬한 후 한 줄에 하나씩 출력한다.🚩제출한 코드
💡TIL
백준 #25195. Yes or yes: DFSBFS / 골드4
정리한 링크: (바로가기)
🚩플로우 (선택)
sys.setrecursionlimit(10**6)을 통해 깊은 재귀 호출이 가능하도록 설정한다.n,m에 따라 각 노드의 간선 정보를 인접 리스트graph에 저장한다.s와 각 팬클럽 노드 정보를 리스트gomgom에 저장한다.False를 반환하여 더이상 탐색을 진행하지 않는다.True를 반환하여 탐색을 종료한다.True라면 경료가 유효하므로 해당 결과를 반환한다.True라면, 팬클럽 곰곰이를 만나지 않고 이동할 수 있는 경우이므로yes를 출력한다.False라면, 어떤 경로든 곰곰이를 만나므로Yes를 출력한다.🚩제출한 코드
💡TIL
사이클이 존재하지 않을 경우에는 그래프를 연결할 때 한 쪽만 연결해주면 된다.
다른 분의 코드를 보고 코드를 보고 파이썬에서도 main 함수 코드를 만들 수 있다는 것을 알게 되었다. 파이썬은 main 함수가 따로 존재하지 않는다. 하지만
if __name__ == '__main__':으로 시작하면 main 함수의 역할을 대신할 수 있다. 즉, python 파일을 재사용ㄱ ㅏ능ㅇ한 모듈 또는 독립 실행형 프로그램으로 사용할 수 있다.출처: https://www.entity.co.kr/entry/51-Python-Main-%ED%95%A8%EC%88%98-%EB%B0%8F-%EB%A9%94%EC%86%8C%EB%93%9C-def-Main%EC%9D%98-%EC%9D%B4%ED%95%B4
재귀 깊이 한도는 그냥 하는 건 줄 알았는데 다른 분의 블로그를 보면서 왜 쓰는지 알게 되었다. 파이썬의 기본 재귀 깊이 제한은 1000이다. 정점의 개수가 1000이 넘어간다면 꼭 재귀 깊이 한도를 설정해주어야 한다.
다른 분의 코드를 보고 내 코드가 너무 쓸데없이 조건이 긴 것 같다는 생각이 들었다. 문제를 푸는 데는 성공했지만 더 나은 코드를 만들기 위해 노력해야겠다.
더이상 탐색할 필요가 없으면
exit(0)를 이용해 프로그램 자체를 종료시키자.백준 #2573. 빙산: DFSBFS / 골드4
정리한 링크: (바로가기)
🚩플로우 (선택)
n과m에 저장한다.iceberg에 저장한다.year변수에 0으로 초기화한다.year를 1 증가시킨다.get_iceberg_height) 를 호출한다.new_height를 초기화한다.water_count를 1증가시킨다.water_count만큼 빙산 높이를 감소시키고 최소 0으로 유지한다.new_height를 반환하고iceberg에 업데이트한다.get_iceberg_height를 호출하여 확인한다.iceberg_count를 0으로 초기화한다.iceberg_count를 1증가시킨다.queue를 초기화하고 첫 위치 방문여부를True로 설정한다.queue가 있는 동안 아래 과정을 반복한다.queue에 추가한다.iceberg_count를 반환한다.iceberg_count가 조건에 맞는지 확인한다.iceberg_count가 2개 이상이면 연도를 출력하고 종료한다.iceberg_count가 0이라면 0을 출력하고 종료한다.🚩제출한 코드
💡TIL
문제 해결을 위한 큰 틀을 미리 정리하는 것이 중요하다는 것을 깨달았다. 처음에는 문제에서 필요한 요소들을 정리하지 않고 무작정 코드를 작성하기 시작했는데, 결국 흐름이 정리되지 않아 코드가 복잡해졌다. 앞으로는 문제의 핵심을 파악하고 필요한 단계를 정리한 후에 코드를 작성해야겠다고 느꼈다.
상하좌우 탐색을 동시에 수행하는 구조를 다루는 데 익숙하지 않아서 시행착오가 있었다. 매년 빙산의 높이를 바다와 인접한 개수만큼 줄이고, 그다음에 BFS로 덩어리를 탐색해야 하는 문제였기에 한 번에 여러 작업을 처리하는 방법을 익히는 데 도움이 되었다.
BFS를 통해 연결된 덩어리 수를 세는 방법을 알게 되었다. 이 문제는 매년 빙산의 덩어리 개수를 확인해야 하는데, BFS로 한 덩어리씩 탐색하면서 방문 처리를 통해 덩어리를 세는 방법을 배울 수 있었다.
2차원 리스트 입력을 간편하게 받는 방식을 새로 알게 되었다. 기존에는 반복문을 통해 2차원 리스트를 하나씩 추가했는데, 한 줄로 리스트를 생성할 수 있어 코드가 훨씬 간결해졌다. 잊지 말고 나중에 유용하게 써먹어야겠다.
백준 #7569. 토마토: DFSBFS / 골드5
정리한 링크: (바로가기)
🚩플로우 (선택)
bfs()함수: 3차원 BFS 탐색 함수all_ripe()함수: 모든 토마토가 있었는지 확인하는 함수3중 for문으로 전체 배열을 순회하며 익지 않은 토마토가 하나라도 있으면
False를, 그렇지 않으면True를 반환한다.메인 코드 흐름:
H,N,M을 입력받아 3차원 배열tomatoes를 생성한다.directions리스트를 설정한다.all_ripe()를 호출해 모든 토마토가 이미 익었으면 0을 출력하고 종료한다.bfs()를 호출하여 최소 일수를 계산하고, 모든 토마토가 익었는지 최종적으로 확인한다.🚩제출한 코드
💡TIL
어려워서 주어진 시간 내에 혼자 처리하지 못하고 결국 도움을 받아 해결하였다.. 접근방식 자체가 어려웠던지라 많이 배우게 된 문제였다. 더불어 너무 어렵게 생각해서는 안 되겠다는 생각이 들었다. 무엇보다 수도코드를 설정하고 접근하면 너무 쉽게 풀릴텐데 수도코드를 처음에 짜는 게 어려운 것 같다. 훈련이 필요한 것 같다.
처음에 3차원으로 입력받는 것이 헷갈려서 아래와 같이 짰는데 입력받는 것을 잘못해서 예제가 제대로 출력이 되지 않았다. 근데 당연히 입력에는 문제가 없을 것이라고 판단하여 로직만 계속 만지작 거렸다.
하지만 3차원 리스트를 한번에 받으려면 아래와 같이 진행하면 된다는 것을 알게 되었다.
n줄만큼 입력하고 나면 h번만큼 반복하여 tomatoes에 추가된다.
BFS 문제에서, 특히 다차원 배열을 다룰 때는 각 차원의 입력을 제대로 다루는 것이 중요하다는 것을 느꼈다.
새로운 BFS 유형을 경험해보게 된 것 같다.
백준 #27961. 고양이는 많을수록 좋다 : 그리디 / 브론즈1
정리한 링크: (바로가기)
🚩플로우 (선택)
n을 입력받는다.n이 0인 경우 0을 출력하고 종료한다.madoka와 현재 고양이 수cat을 각각 1로 초기화한다.cat이 목표 고양이 수n보다 같거나 커질 때까지 계속해서 복제 마법(cat *= 2)을 사용하고, 행동 횟수madoka를 증가시킨다.cat이n과 같아지거나 이를 초과하면 반복을 종료하고madoka를 출력한다.🚩제출한 코드
💡TIL
백준 #14917. 거스름돈: 그리디 / 실버5
정리한 링크: (바로가기)
🚩플로우 (선택)
"가능한 한 5원짜리 동전을 우선 사용하고, 나머지를 2원짜리로 채운다."
n을 입력받는다.n이 5보다 크고(n-5)를 한 값이 5의 배수거나 짝수일 경우는 5를 뺀다. 그게 아닐 경우 2를 뺀다. 이 과정을n이 0보다 클 동안 반복하며, 한 번 반복할 때마다cnt를 1 증가시킨다.cnt를 출력한다.1~9원까지는 규칙성이 없으나 10원부터는 i원은 [i-5]원 값에 +1한 값과 같다.
따라서 점화식은 다음과 같다.
n을 입력받는다.n이 5보다 크고(n-5)를 한 값이 5의 배수거나 짝수일 경우는 5를 뺀다. 그게 아닐 경우 2를 뺀다. 이 과정을n이 0보다 클 동안 반복하며, 한 번 반복할 때마다cnt를 1 증가시킨다.cnt를 출력한다.🚩제출한 코드
그리디
DP
💡TIL