김호쭈
DevForYou
김호쭈
전체 방문자
오늘
어제
  • 분류 전체보기 (321)
    • • 데이터베이스(DB) (9)
      • __SQL__ (9)
    • •알고리즘(Algorithm ) (117)
      • 문제풀이 (99)
      • 스터디 (14)
      • 알고리즘 팁 (4)
    • •Compter Science (57)
      • Operating System (25)
      • Computer Network (1)
      • Computer Vision (16)
      • Artificial Intelligence (14)
      • Software Technology (1)
    • • 독서 (36)
      • Design Pattern (24)
      • 객체지향의 사실과 오해 (1)
      • Object Oriented Software En.. (11)
    • • 개발 (26)
      • React (3)
      • node.js (6)
      • Django (11)
      • Spring boot (6)
    • • 개발Tip (4)
      • GitHub (0)
    • •프로젝트 (2)
      • 물물 (2)
    • •App (54)
      • 안드로이드 with Kotlin (50)
      • 코틀린(Kotiln) (4)
    • •회고 (8)
    • •취준일기 (3)
    • • 기타 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • local저장소
  • ㄱ
  • 깃허브데스크탑
  • 원격저장소
  • GitHubDesktop
  • KMU_WINK
  • 로컬저장소
  • Remote저장소

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
김호쭈

DevForYou

•알고리즘(Algorithm )/문제풀이

[백준1939&파이썬] 이진탐색 BFS에 응용하기, 이진탐색 경계값 설정에 주의하자.

2023. 4. 27. 02:30

# 문제

백준1939 중량제한 파이썬 풀이

 

1939번: 중량제한

첫째 줄에 N, M(1 ≤ M ≤ 100,000)이 주어진다. 다음 M개의 줄에는 다리에 대한 정보를 나타내는 세 정수 A, B(1 ≤ A, B ≤ N), C(1 ≤ C ≤ 1,000,000,000)가 주어진다. 이는 A번 섬과 B번 섬 사이에 중량제한이

www.acmicpc.net

# 코드

'''
  - 노드간 여러개 엣지가 존재 할 수 있다.
  - 양방향 다리이다.
  - DFS + 백트래킹을 활용해서 길의 최대값을 구한다 -> 시간초과 or 메모리 초과
  - 모든 경우의 수를 구하고 거기서 최대값을 구한다 -> 시간초과 or 메모리 초과
  - 이분탐색 시간복잡도 -> O(logN)
    - 0 ~ 10억의 경우의 수에서 해당 값을 경로가 넘어버리는지 아닌지를 확인한다
    - O(log 10억) 은
    - 도착점까지의 길은 무조건 있다.
'''
import sys
from collections import defaultdict
from collections import deque

MAX = 1_000_000_000  # 10억
N, M = map(int, sys.stdin.readline().split())  # N : 노드, M : 엣지
graph = defaultdict(list)
# graph = [[] for _ in range(N + 1)]

for _ in range(M):
  a, b, c = map(int, sys.stdin.readline().split())
  # 양방향 다리
  graph[a].append((b, c))
  graph[b].append((a, c))


start, end = map(int, sys.stdin.readline().split())
left = 1
right = MAX
result = -1
while left <= right:
  mid = (left + right) // 2  # 이 값이 중량 값임, 이값으로 도착이 가능한지 판단하면 됨

  # 도착점까지의 길이 무조건 있기 때문에, mid값보다 크거나 같은 간선만 선택해서 가자
  dq = deque()
  dq.append(start)
  visit = [False] * (N + 1)
  visit[start] = True
  isFinish = False

  while len(dq) != 0:
    cur = dq.popleft()
    for neighbor in graph[cur]:  # neighbor : (vertex, cost)
      if mid <= neighbor[1]:
        if visit[neighbor[0]] == False:  # 방문했던 곳이 아니라면
          visit[neighbor[0]] = True
          dq.append(neighbor[0])

          if neighbor[0] == end:  # 도착했으면, 범위를 키워봄
            left = mid + 1
            isFinish = True
            dq.clear()
            result = mid
            break
  if not isFinish :
    right = mid - 1  # 도착을 못했기 때문에 범위를 줄임

print(result)

# 풀이

  • DFS(백트래킹)을 사용해서 끝까지 계속 도달시키는 값을 확인하고, 끝점에 도착했을때 값보다 더 크게 움직여야지만 가능하도록 하는 코드를 작성했으나 시간초과가 발생했다.
  • 이분탐색을 이용해서 문제를 해결 할 수 있다. 간선의 갯수가 최대 10억개까지이기 때문에 완전탐색으로 모든 경우를 구하는 것은 당연히 불가능하다.
  • 그렇다면 이분탐색으로 선택된 MID의 대해서 현재 BFS로 탐색했을 시, MID값 이상을 넘기는지 못넘기는지 YES / NO 의 여부로 판단하여 최적의 값을 찾아내면 된다. start=1 , end = 10억으로 하여 찾는 최적의 cost를 이분탐색을 진행한다. 이분탐색의 시간복잡도는 O( log C ) 이다.(C는 10억) 그렇기 때문에 29번의 탐색만 거치면 값을 찾아낼 수 있다. 
  • 결국 29 * O( V + E )  = O( 29 ) * O ( 10,000 + 100,000 ) 이기 때문에 적정 시간안에 탐색을 끝낼 수 있다.

## 삽질

  • 이분탐색 경계설정을 잘못하고 있어서 시간초과가 났고, 1시간동안 헤맸다.
  • binary(left,right) 일때, 경계값 넘겨주는걸 left = mid -1 , right = mid로 해줬다. 왜냐하면 성공했을 경우 mid일 수도 있다는 생각이었다. 그러고 while문 탈출 조건을 left != mid로 해줬었는데 여기서 계속 무한루프에 빠졌다. 
    • 왼쪽으로 재탐색 해야하는 경우 right = mid -1 
    • 오른쪽으로 재탐색 해야하는 경우 left = mid 
    • 탈출 조건 left != right
  • 위의 케이스처럼이 아닌 아래와 같이 수정했더니 정답이 됐다.
    • 왼쪽으로 재탐색 해야하는 경우 right = mid -1
    • 오른쪽으로 재탐색 해야하는 경우 left = mid +1
    • 탈출 조건 left <= right 

 

  • 이진탐색의 경계 조건이 생각보다 헷갈리는거 같다. 시간날때 공부해야겠다. 
 

Binary Search Lower Bound와 Upper Bound

이진검색은 많은 곳에서 사용되는데 의외로 Lower Bound와 Upper Bound 문제가 나오면 정확한 코드를 만들지 못해서 쉬운 풀이임에도 틀리는 경우가 많고 오류가 많이 난다. 그래서 이번 기회에 Bound에

enumclass.tistory.com

# 참고

공장끼리 연결하는 섬의 경로가 항상 존재하기 때문에 크루스칼을 사용하여 MST(이런 경우에는 MAX SPANNING TREE )을 찾아도 해결이 가능하다.

 

 

저작자표시 (새창열림)

'•알고리즘(Algorithm ) > 문제풀이' 카테고리의 다른 글

[백준2294&파이썬] DP를 이용하여 동전교환문제를 해결하기, DP는 값을 재활용한다.  (0) 2023.04.28
[백준2512&파이썬] 이분탐색은 YES or NO인지 묻는 것이다.  (0) 2023.04.28
[백준16236&파이썬] BFS을 작은단위로 쪼개 생각하자. 종료조건과 탐색조건을 잘 생각하자.  (0) 2023.04.26
[백준6497&파이썬] 크루스칼은 최소신장트리를 구할 수 있다.  (0) 2023.04.26
[백준1647&파이썬] 크루스칼 알고리즘을 이용한다면 최소신장트리(MST)를 찾을 수 있다.  (0) 2023.04.26
    '•알고리즘(Algorithm )/문제풀이' 카테고리의 다른 글
    • [백준2294&파이썬] DP를 이용하여 동전교환문제를 해결하기, DP는 값을 재활용한다.
    • [백준2512&파이썬] 이분탐색은 YES or NO인지 묻는 것이다.
    • [백준16236&파이썬] BFS을 작은단위로 쪼개 생각하자. 종료조건과 탐색조건을 잘 생각하자.
    • [백준6497&파이썬] 크루스칼은 최소신장트리를 구할 수 있다.
    김호쭈
    김호쭈
    공부하고 정리하고 기록하기

    티스토리툴바