Skip to content

Conversation

@zaqquum
Copy link
Collaborator

@zaqquum zaqquum commented May 3, 2025

🌱WIL

이번 한 주의 소감을 작성해주세요!

  • 이번 주는 매개변수 탐색과 그래프 위주의 문제를 풀었다. 특히 이진 탐색의 심화버전인 매개변수 탐색은 시간제약이 걸려있어 백준의 시간복잡도 계산 방법에 대해서도 고민하는 시간이 되었다.

🚀주간 목표 문제 수: 5개

푼 문제


백준 #2110. 공유기 설치: 이진탐색/ 골드4

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. N개 집 위치 오름차순 정렬

  2. “최소 거리 dist”의 탐색 범위 초기화 # 이진 탐색

    start = 1

    end = arr[-1] - arr[0]

    mid = (start+ene)//2

  3. 최대 인접거리 dist의 최대값을 찾기 위한 이진 탐색 수행 ( start ≤ end 까지 반복)

    (1) “최소거리 dist = mid 이상”으로 최대한 설치 가능한 공유기 개수 계산하기

    1. 첫번째 집은 시작점(즉, 무조건 공유기 설치),
    2. for 문으로 설치할 집 탐색
      • 현재 설치할 지점과 이전에 설치한 지점prev 간의 거리가 mid 이상이면
        → 설치 (cnt+=1)+ prev = arr[i] 이전 설치지점 업데이트
      • 그렇지 않으면 , 다음 지점 (arr[i+1]) 으로 이동

    (2) 최소 인접거리 dist 의 이분 탐색

    • 설치한 공유기 개수가 C 이상인 경우,
      최소 인접거리 후보군 등록
    • 매개변수 탐색 범위 upper bound 로 이동
      (탐색 시작 지점 start → mid +1 이동 )
    • 그렇지 않을 경우 , 탐색 범위 lower bound 로 이동

      (탐색 종료 지점 end → mid-1 이동)

🚩제출한 코드

import sys 
input = sys.stdin.readline

#1. 입력 변수 + 오름차순 정렬
N , C  = map(int, input().split())
arr =sorted([int(input()) for _ in range(N)])

#2. “최소 거리 dist”의 탐색 범위 초기화 # 이진 탐색
start = 1 ; end = arr[-1] - arr[0] 
answer = 0  # 최소 거리 중 최대 거리 

#3.최소 인접 거리 dist 최대값 찾기
#설치 공유기는 dist이상의 간격으로 설치
while start <= end : 
  mid = (start+end)//2
  cnt = 1 # arr[0]은 설치 시작점
  
  #[1] 최소 인접 거리가 mid 이상으로 "최대 설치 가능 공유기 개수계산"
  prev = arr[0] # 이전에 설치한 공유기 위치
  for i in range(1,N) :
    if arr[i] - prev >= mid : # 공유기 등록
      prev = arr[i]
      cnt+=1 
    # 공유기 등록하기엔 dist부족한 경우 -> 다음 arr로 이동 

  #[2] 최소거리 dist 이분 탐색
  # 조건 : 설치한 공유기 개수 Cnt 가 C 이상
  # True 경우 ,  최소거리 Answer 업데이트, 탐색 범위 (mid+1 : end) 이동
  if cnt >= C :
    answer = max(answer ,mid)
    start = mid+1
  # False 경우: 탐색 범위 Lower bound로 이동(start : mid)
  else : 
    end = mid - 1

print(answer)

💡TIL

매개변수 탐색 : 유한 & 연속 범위의 최적화 문제를 결정 문제 (T/F)로 변환하는 이진 탐색 방법

  • 이진탐색과 달리, <조건>을 충족하는 중간값을 찾아도, 중단하지 않고 모든 범위를 탐색한다.

백준 #1654. 랜선 자르기: 이진탐색 / 실버2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

🚩제출한 코드

K, N = map(int, input().split())

lines = [int(input()) for _ in range(K)]
# 1. 범위 초기화
start = 1
end = max(lines)
#2. 이분 탐색
while start <= end:
    mid = (start + end) // 2
    cnt = 0
    for line in lines:
        cnt += line // mid

    if cnt < N:
        end = mid - 1
    else:
        start = mid + 1

print(end)

프로그래머스 #169199. 리코쳇 로봇: 그래프 / lv2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 필드 board을 2차원 배열 field 로 변환

    • field 초기값 = INF
    • Start , Target 지점 좌표 & 장애물 위치 (field[i][j] = -1) 값 입력
  2. 다음 이동 지점 함수 정의

    • 다음 이동할 지점 = 상/하/좌/우 중 한 방향으로 장애물 or 가장자리에 도달할때 까지 이동

      (일반적인 상하좌우 1칸씩 이동이 아님)

  3. BFS로 탐색

    • q 와 field 초기화
      • q= [start], field[s[0]][s[1]] = 0 # 최소 턴수
    • 상하좌우로 중 한 방향으로 도달한 지점에 걸린 최소 턴수를 field 값에 기입
    • 현재 탐색한 지점이 목표 지점이면 중간에 while 반복문 탈출
  4. 출력 형식

    • 목적지 target 지점에 field 값이 INF 면 → 도달 모함 : -1 출력
    • 이하면 → 목적지 도달함 : field 값 출력

🚩제출한 코드

"""
#문제 다 읽고 수도 코드 짜자
- goal) 시작 R => 목표 G 까지 최소 이동 수 구하기(도달 못하면 -1 )
- 상하좌우로 "장애물, 가장자리"에 부딫칠 떄까지 이동 = 1회 이동 => 외곽& 장애물 = field[-1]
- board 는 text로 주어짐 => 2차원 배열로 변환 
# flow - BFS : 최단 거리
- 이동 방법
"""
from collections import deque
INF = 1e9
def solution(board):
    answer = 0
    #1. 필드 board 정보를 2차원 배열로 변환(장애물 -1/ 없음 0 )
    N , M = len(board) , len(board[0])
    field = [[INF]*M for _ in range(N)]
    
    for i in range(N) :
        for j in range(M) :
            if board[i][j] == "R":
                start = [i,j]
            elif board[i][j] == "G":
                target = [i,j]
            elif board[i][j] == "D":
                field[i][j] = -1
                # print("break",field[i][j])
    #2. 탐색 
    # print(start , target ,field)
    #상하좌우
    dy = [-1, 1, 0,0] 
    dx = [0,0,-1,1]
    def move_node(d, start): # 이동 방향 ,출발점
        ny , nx = start ; flag = False # flag : 최소 이동 여부(Y/N)
        while 0<= ny + dy[d]< N and 0<= nx+dx[d] < M and field[ny + dy[d]][nx+dx[d]] >= 0 : # 장애물, 가장자리x 
            ny += dy[d] ; nx += dx[d]
            flag = True
        return ny ,nx , flag
    # 시작점 초기화
    q= deque([start])
    field[start[0]][start[1]] = 0 
    cnt = 0 
    while q : 
        cy,cx = q.popleft()
        if [cy,cx] == target : #(옵션)효율성
            break)
        for di in range(4):
            cnt += 1 
            ny,nx,f = move_node(di, [cy,cx])
            if f and field[ny][nx] == INF : # 해당 [ny,nx] 에 처음 도착(방문x) & 해당 지점에 이동 가능할 경우 
                field[ny][nx] = min(field[ny][nx], field[cy][cx]+1)
                # min은 필요 없음(BFS로 가장먼저 field에 입력 된 턴수가 최소 이동수 )
                # field안에 최소 이동 턴수 기록
                q.append([ny,nx])

    #3. 출력
    answer=field[target[0]][target[1]]
    # target지점 값에 업데이트가 없음 -> 도달 못함 : -1 / 최소 이동 턴수
    if answer >= INF : 
        answer = -1
    return answer

💡TIL

(회고) 문제는 다 읽고 접근하자
- 스킬체크로 나온 문제로, 당시 시간에 쫒긴 나머지, 문제 읽기와 코드 작성을 병행하다 “상하좌우 무한 이동”이란 조건을 빼먹음
- 적어도 문제 요구 사항은 다 파악하고 Step1 입력 변수 정의 & Flow 작성하자

프로그래머스 #87946. 피로도: 완전탐색 / lv2

정리한 링크: (바로가기)

🚩플로우 (선택)

재귀를 활용한 완전 탐색

🚩제출한 코드

def solution(k, dungeons):
    max_count = 0 
    def brutefoce(path, life):
        nonlocal max_count 
        for idx in range(len(dungeons)):
            # (유망 여부) 조건에 안 맞으면 건너뛰기 : limit 제한 , 중복 탐사 방지
            if dungeons[idx][0] <= life and  idx not in path:
                # 3. 탐색할 노드 선택 - 상태 변화  
                path.append(idx)
                # 4. 재귀 호출(담 단계) - 자식 노드로 이동
                brutefoce(path ,life -dungeons[idx][1])
                # 5. 선택 취소 - 부모 노드로 복귀
                path.pop()
        max_count = max(max_count , len(path))
    brutefoce([], k )

    return max_count

💡TIL

  • global : 전역 변수
    -nonlocal : 본인 스코프 반대 방향으로 가장 가까운 변수를 찾는다(전역변수은 찾지 않음 )

프로그래머스 #70129. 이진변환 반복하기: 문자열 / lv2

정리한 링크: (바로가기)

🚩제출한 코드

def solution(s):
    answer = []
    # 1. 문자열 속 모든 "0" 제외하기 & 제외한 0 개수 누적 합
    # 2. 남은 문자열 크기의 값을 이진수 변환 
    #3. 변환된 이진수를 다시 [1]번의 입력으로 넣어 반복(문자열 길이가 1이 될때 까지) 
    
    a = 0 
    rotate = 0 
    while len(s) > 1 :
        cnt = 0
        for n in s : 
            if n == "0" :
                a+=1
                continue
            cnt +=1

        s= str(bin(cnt))[2:]
        rotate += 1
    
    answer = [rotate , a]
    return answer

Copy link
Collaborator

@Mingguriguri Mingguriguri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

홍주님 문제 5개나 푸신 것... 정말 리스펙입니다!! 매번 자극받고 가요 ㅎㅎ(자극만 받아서 문제ㅠ)
매개변수 탐색이라는 유형을 보고 새로운 시각을 얻은 느낌이었습니다. 좋은 문제 준비해주셔서 감사해용!!

Copy link
Member

@YoonYn9915 YoonYn9915 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이분탐색에 대해 깊게 생각해 볼 수 있는 문제들이었던거 같습니다. 수고하셨습니다!

@Mingguriguri Mingguriguri merged commit e448868 into main May 6, 2025
@github-actions
Copy link

github-actions bot commented May 6, 2025

🔥2025-05 챌린지 진행 상황

👉 그래프

  • YoonYn9915: 0개 ❌
  • Mingguriguri: 2개 ❌
  • zaqquum: 1개 ❌

👉 DP

  • YoonYn9915: 2개 ❌
  • Mingguriguri: 0개 ❌
  • zaqquum: 0개 ❌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants