BFS(Breadth First Search) 너비 우선 탐색

  • 가중치가 없는 그래프에서 시작점에서 끝점까지의 최단 경로를 찾을 수 있다.
    • 가중치가 있는 그래프에서는 '다익스트라' 알고리즘 사용
  • 주로 Queue를 이용해서 구현한다.
  • 노드의 개수 N, 시간복잡도 O(N)

 

구현 과정

  • 탐색을 시작하는 칸을 큐에 넣고 방문 처리
  • 큐에서 pop해서 방문하지 않은 노드의 상하좌우로 인접한 노드 정보를 모두 큐에 넣고 현재 노드(pop한 노드) 방문처리 한다.
  • 큐가 빌때까지 반복

 

BFS 문제 - 1926번 그림

https://www.acmicpc.net/problem/1926

 

1926번: 그림

어떤 큰 도화지에 그림이 그려져 있을 때, 그 그림의 개수와, 그 그림 중 넓이가 가장 넓은 것의 넓이를 출력하여라. 단, 그림이라는 것은 1로 연결된 것을 한 그림이라고 정의하자. 가로나 세로

www.acmicpc.net

from collections import deque

n, m = map(int, input().split())  # 세로, 가로
board = [list(map(int, input().split())) for _ in range(n)]
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
answer = []  # 넓이를 저장할 리스트


# 그림의 개수, 가장 큰 넓이 출력
# 그림 = 1로 연결된 것,

def bfs(x, y):  # 탐색 위치, 넓이
    # 그림이 시작 하는 위치에서 큐 시작
    board[x][y] = 0  # 현재 위치 방문 체크
    queue = deque()  # 큐 생성
    queue.append([x, y])  # 큐에 해당 칸 넣기
    cnt = 1  # 그림 칸 개수
    while queue:  # 큐가 빌때까지
        a, b = queue.popleft()  # 현재 탐색 위치 제거(탐색 완료)
        for d in range(4):  # 상하좌우 확인
            nx = a + dx[d]
            ny = b + dy[d]
            # 2차원 배열에서 벗어나지 않고, 다음 위치가 1(그림이 있는)인 경우
            if -1 < nx < n and -1 < ny < m and board[nx][ny] == 1:
                board[nx][ny] = 0  # 다음 위치 방문 체크
                queue.append([nx, ny])  # 큐에 탐색할 위치 넣기
                cnt += 1  # 그림 칸 개수
    return cnt


# 그림의 시작점 찾기
for i in range(n):
    for j in range(m):
        if board[i][j] == 1:  # 그림이 있는 위치
            answer.append(bfs(i, j))

if len(answer) == 0: # 그림이 하나도 없는 경우
    print(len(answer))
    print(0)
else:
    print(len(answer))
    print(max(answer))

 

 

BFS 문제 -2667번 단지번호붙이기

https://www.acmicpc.net/problem/2667

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

from collections import deque

n = int(input())
board = [list(map(int, input())) for _ in range(n)]
answer = []
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]


# 1 집이 있는곳, 0 집이 없는 곳
# 단지 개수, 단지에 속하는 집 개수 출력

def bfs(x, y):
    queue = deque()
    queue.append([x, y])
    board[x][y] = 0  # 방문체크
    cnt = 1

    while queue:
        px, py = queue.popleft()

        for d in range(4):
            nx = px + dx[d]
            ny = py + dy[d]

            # 방문 가능한 곳인지 확인
            if 0 <= nx < n and 0 <= ny < n and board[nx][ny] == 1:
                board[nx][ny] = 0  # 다음 방문 체크
                queue.append([nx, ny])  # 큐 입력
                cnt += 1
    return cnt  # 집 개수 출력


for i in range(n):
    for j in range(n):
        if board[i][j] == 1:
            answer.append(bfs(i, j))

answer.sort()
print(len(answer))
for x in answer:
    print(x)

 

 

BFS 문제 - 2178번 미로 탐색

https://www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

from collections import deque

n, m = map(int, input().split())  # 가로, 세로
board = [list(map(int, input())) for _ in range(n)]

# 1: 이동할 수 있는 칸, 0: 이동 불가능
# (1,1)에서 출발 (N,M) 위치로 이동할 때 지나야 하는 최소 칸 수 출력

def bfs(x, y):
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]
    queue = deque()  # 큐 생성
    queue.append([x, y])  # 시작점 체크
    while queue:
        a, b = queue.popleft()

        for d in range(4):
            nx = a + dx[d]
            ny = b + dy[d]

            # 방문 가능한 곳
            if 0 <= nx < n and 0 <= ny < m and board[nx][ny] == 1:
                queue.append([nx, ny])  # 큐 삽입
                board[nx][ny] = board[a][b] + 1
    return board[n - 1][m - 1]

print(bfs(0,0))

 

 

BFS 문제 - 7576번 토마토

https://www.acmicpc.net/problem/7576

 

7576번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토

www.acmicpc.net

from collections import deque

m, n = map(int, input().split())  # 가로, 세로
board = [list(map(int, input().split())) for _ in range(n)]
visited = [[0 for _ in range(m)] for _ in range(n)]
queue = deque()
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]
day = 0

# 토마토는 하루가 지날 때 마다 안익은 토마토는 인접한 익은 토마토의 영향을 받아 익게 된다.
# 모든 토마토가 익게 되는 일수 출력, 모두 익지 못하는 상황에는 -1 출력
# 익은 토마토 1, 안익은 토마토 0, 토마토가 없는 경우 -1
# 시작 위치 큐에 넣기
for i in range(n):
    for j in range(m):
        if board[i][j] == 1:
            queue.append([i, j])

def bfs():
    while queue:
        px, py = queue.popleft()

        for d in range(4):
            nx = px + dx[d]
            ny = py + dy[d]

            # 토마토가 익지 않았을 경우
            if 0 <= nx < n and 0 <= ny < m and board[nx][ny] == 0:
                board[nx][ny] = board[px][py] + 1
                queue.append([nx, ny])


bfs()

# 익지 않은 토마토가 있으면 -1 출력, 모두 다 익은 경우 가장 큰 날짜를 찾아서 출력
for i in range(n):
    for j in range(m):
        if board[i][j] == 0:
            print(-1)
            exit(0)
    maxValue = max(board[i])
    day = max(maxValue, day)

# 처음 시작을 1로 했기 때문에 -1
print(day-1)

 

 

https://www.acmicpc.net/problem/4179

 

4179번: 불!

입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다. 다음 입력으로 R줄동안 각각의 미로 행이 주어진다.  각각의 문

www.acmicpc.net

 

https://www.acmicpc.net/problem/1697

 

1697번: 숨바꼭질

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

from collections import deque
#n, k = 5, 17 # 수빈이가 있는 위치, 동생이 있는 위치
n, k = map(int, input().split())
MAX = 10 ** 5
visited = [0]*(MAX+1)
# 걷기 : 1초 후 x-1, x+1로이동
# 순간이동 : 1초 후 2*x 으로 이동
# 가장 빠른 시간 찾기

def bfs():
    queue = deque()
    queue.append(n)
    while queue:
        x = queue.popleft()

        if x == k:
            print(visited[x])
            break
        for nx in (x-1, x+1, x*2):
            if 0 <= nx <= MAX and not visited[nx]:
                visited[nx] = visited[x] + 1
                queue.append(nx)

bfs()

 

 

https://www.acmicpc.net/problem/14502

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

 

https://www.acmicpc.net/problem/16236

 

16236번: 아기 상어

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가

www.acmicpc.net

 

https://www.acmicpc.net/problem/2638

 

2638번: 치즈

첫째 줄에는 모눈종이의 크기를 나타내는 두 개의 정수 N, M (5 ≤ N, M ≤ 100)이 주어진다. 그 다음 N개의 줄에는 모눈종이 위의 격자에 치즈가 있는 부분은 1로 표시되고, 치즈가 없는 부분은 0으로

www.acmicpc.net

 

https://www.acmicpc.net/problem/2146

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다

www.acmicpc.net

 

동적 계획법(Dynamic Programming)

  • 최적화 이론의 한 기술
  • 특정 범위까지의 값을 구하기 위해서 그것과 다른 범위까지의 값을 이용하여 효율적으로 값을 구하는 알고리즘
  • 어떤 문제를 풀기 위해 그 문제를 더 작은 문제의 연장선으로 생각하고, 과거에 구한 해를 활용한다.
  • ex. 피보나치 수열에서 중복된 연산을 미리 배열을 만들어두고 값을 저장해두면(메모이제이션) 시간 복잡도 O(N)으로 개선 가능
  • 상향식 접근법 : for으로 구현, 작은 문제를 모아 큰 문제 해결, 메모제이션 사용X
  • 하향식 접근법 : 재귀함수 구현, 큰 문제를 해결하기 위해 작은 재귀 함수 호출, 메모제이션 사용
  • 보통 동적 계획법은 상향식 접근법을 사용

 

DP를 푸는 과정

  1. 테이블 정의하기
  2. 점화식 찾기
  3. 초기값 정하기

DP 문제 - 1463번 1로 만들기

  • 정수 N이 주어질 때, 세 개의 연산을 적절히 사용해서 1을 만드려고 한다. 연산 사용 횟수의 최소값 구하기 

1. 테이블 정의하기

  • D[i] = i를 1로 만들기 위해 필요한 연산 사용 횟수의 최솟값

2. 점화식 찾기

  • D[12] = ?
  • 3으로 나누거나 D[12] = D[4] + 1
  • 2으로 나누거나 D[12] = D[6] + 1
  • 1을 빼거나 D[12] = D[11] + 1
  • D[12] = min(D[4] + 1, D[6] + 1, D[11] + 1)

3. 초기값 정의하기

  • D[1] = 0
n = int(input()) # 정수 N
dp = [0]*(n+1) # dp에 계산된 값을 저장해두고
dp[1] = 0

for i in range(2, n+1):
    dp[i] = dp[i-1] + 1
    if i % 3 == 0: dp[i] = min(dp[i], dp[i//3]+1)
    if i % 2 == 0: dp[i] = min(dp[i], dp[i//2]+1)

print(dp[n])

DP 문제 - 9095번 1,2,3 더하기

  • 정수 n이 주어질 때, n을 1,2,3의 합으로 나타내는 방법의 수 구하기

1. 테이블 정의하기

  • D[i] = i를 1,2,3의 합으로 나타내는 방법의 수

2. 점화식 찾기

  • D[4] = ?
  • 1+1+1+1, 3+1, 2+1+1, 1+2+1 // (3을 1,2,3 합으로 나타내는 방법) + 1, D[3]
  • 1+1+2, 2+2 // (2를 1,2,3 합으로 나타내는 방법) + 2, D[2]
  • 1+3 // (1을 1,2,3 합으로 나타내는 방법) + 3, D[1]
  • D[4] = D[1] + D[2] + D[3]

3. 초기값 정의하기

  • D[1] = 1, D[2] = 2, D[3] = 4 방법의 개수 
  • D[i] = D[i-1] + D[i-2] + D[i-3]
tc = int(input())

for _ in range(tc):
    n = int(input())
    if n == 1:
        print(1)
    elif n == 2:
        print(2)
    elif n == 3:
        print(4)
    else:   
        dp = [0] * (n + 1)
        dp[1], dp[2], dp[3] = 1, 2, 4
        for i in range(4, n + 1):
            dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
        print(dp[n])

DP 문제 - 2579번 계단 오르기

  • 각 계단에 쓰여 있는 점수가 주어질 때 게임에서 얻을 수 있는 총 점수의 최대값 구하기

1. 테이블 정의하기

  • D[i][j] = 현재부터 j개의 계단을 연속해서 밟고 i번째 계단에서 얻을 수 있는 점수 합의 최대값 + i번째 계단은 반드시 밟아야 한다.
  • (연속된 세 계단을 모두 밟아서는 안되는 제약조건) 

2. 점화식 찾기

  • D[k][1] = max(D[k-2][1], D[k-2][2]) + S[k] // 1개의 계단을 연속해서 밟고, k번째 계단까지 최대값 
    • 1개의 계단을 밟았다 = k-1번째는 밟지 않았다. = k-2번쨰는 무조건 밟았다.
    • S[k] : k번째 계단 점수
  • D[k][2] = D[k-1][1] + S[k] // 2개의 연속된 계단을 밟고, k번째 계단까지 최대값
  • j는 3개 연속이 불가능하기 때문에 3 이상일 수 없다.

3. 초기값 정의하기

  • D[1][1] = S[1], D[1][2] = 0
  • D[2][1] = S[2], D[2][2] = S[1] + S[2]
n = int(input()) # 계단의 개수
S = [0]*(n+1)
for i in range(1, n+1):
    S[i] = int(input())

if n == 1:
    print(S[1])
elif n == 2:
    print(S[1]+S[2])
else:
    dp = [[0 for col in range(3)] for row in range(n+1)]
    dp[1][1], dp[1][2] = S[1], 0
    dp[2][1], dp[2][2] = S[2], S[1]+S[2]
    # 계단 오르기 규칙
    # 1. 한 계단 또는 두 계단 오르기 가능
    # 2. 연속 세개 계단 불가능(시작점은 포함X)
    # 3. 마지막 계단 무조건 밟기

    for i in range(3,n+1):
        dp[i][1] = max(dp[i-2][1], dp[i-2][2]) + S[i]
        dp[i][2] = dp[i-1][1] + S[i]

    print(max(dp[n][1], dp[n][2]))

DP 문제 - 1149번 RGB거리

  • 집의 색상은 빨강, 초록, 파랑 중 하나의 색상
  • 집을 빨강, 초록, 파랑으로 칠하는 비용이 주어질 때, 규칙을 만족하면서 모든 집을 칠하는 비용의 최솟값 구하기

1. 테이블 정의하기

  • D[i][0] = i번째 집까지 칠할 때 비용의 최솟값, i번째 집은 빨강
  • D[i][1] = i번째 집까지 칠할 때 비용의 최솟값, i번째 집은 초록
  • D[i][2] = i번째 집까지 칠할 때 비용의 최솟값, i번째 집은 파랑

2. 점화식 찾기

  • D[k][0] = min(D[k-1][1], D[k-1][2]) + R[k] // 빨강으로 칠할 때 k-1 집은 초록 or 파랑 + R[k] 빨강 비용
  • D[k][1] = min(D[k-1][0], D[k-1][2]) + G[k] // 초록으로 칠하면 빨강 or 파랑
  • D[k][2] = min(D[k-1][0], D[k-1][1]) + B[k] // 파랑으로 칠하면 빨강 or 초록

3. 초기값 정하기

  • D[1][0] = R[1]
  • D[1][1] = G[1]
  • D[1][2] = B[1]
n = int(input())  # 집 개수
R = [0] * (n + 1)
G = [0] * (n + 1)
B = [0] * (n + 1)
dp = [[0 for col in range(3)] for row in range(n + 1)]
for i in range(1, n + 1):
    color = list(input().split())
    R[i] = int(color[0])
    G[i] = int(color[1])
    B[i] = int(color[2])

if n == 1:
    print(min(R[1], G[1], B[1]))

else:
    # 초기값 설정
    dp[1][0] = R[1]
    dp[1][1] = G[1]
    dp[1][2] = B[1]
    # 집 색칠 규칙
    # 1. 1번의 집 색상은 2번의 집 색상과 같지 않아야 한다.
    # 2. N번 집의 색상은 N-1번의 집 색상과 같지 않아야 한다.
    # 3. 2(<= i <= N-1)번의 집 색상은 i-1번, i+1번 집의 색상과 같지 않아야 한다.

    for k in range(2, n + 1):
        dp[k][0] = min(dp[k - 1][1], dp[k - 1][2]) + R[k] # 이전색상 초록 or 파랑 + 현재 빨강
        dp[k][1] = min(dp[k - 1][0], dp[k - 1][2]) + G[k] # 이전색상 파랑 or 빨강 + 현재 초록
        dp[k][2] = min(dp[k - 1][0], dp[k - 1][1]) + B[k] # 이전색상 빨강 or 파랑 + 현재 파랑

print(min(dp[n][0], dp[n][1], dp[n][2]))

DP 문제 - 11726번 2xn 타일링

  • 2xn 크기의 직사각형을 1x2, 2x1 타일로 채우는 방법의 수를 구하기

1. 테이블 정의하기

  • D[i] = 2xi 크기의 직사각형을 채우는 방법의 수

2. 점화식 찾기

  • D[i] = D[n-1] + D[n-2]
  • 2 x 1 타일로 1개씩 채우면 남는 방법의 수 n-1
  • 1 X 2 타일로 2개 채우면 남는 방법의 수 n-2

3. 초기값 정하기

  • D[1] = 1
  • D[2] = 2
n = int(input())
dp = [0]*1001

dp[1] = 1
dp[2] = 2

for i in range(3, 1001):
    dp[i] = (dp[i-1] + dp[i-2]) % 10007
print(dp[n])

 

DP 문제 - 11659번 구간 합 구하기 4

  • dp[i] = arr[1] + arr[2] + arr[3] + .. + arr[i]
  • dp[i] = dp[i-1] + arr[i]
import sys
n, m = map(int, sys.stdin.readline().split()) # 수의 개수, 합을 구해야하는 횟수
arr = list(map(int, sys.stdin.readline().split()))
dp = [0]*(n+1)
# D[i] = A[1] + A[2] + .. + A[i]
# D[i] = D[i-1] + A[i]
for i in range(1, n+1):
    dp[i] = dp[i-1] + arr[i-1]

for _ in range(m):
    i, j = map(int, sys.stdin.readline().split())
    print(dp[j]-dp[i-1])

자료구조(Data Structure)

  • 효율적인 접근 및 수정을 가능하게 하는 자료의 조직, 관리, 저장
  • 데이터 값의 모임, 데이터 간의 관계, 데이터에 적용할 수 있는 함수나 명령
  • 자료구조를 통해 효율적인 알고리즘을 사용할 수 있다.

 

구현에 따라

  • 배열 - 일반적인 구조. 같은 타입형의 자료가 연속으로 저장된다.
  • 튜플 - 둘 이상의 자료형을 묶음으로 다루는 구조
  • 연결 리스트 - 노드를 단위로, 노드는 자료와 다음 노드를 가리키는 참조 값으로 구성되어 있따.
  • 해시 테이블 - 개체가 해시 값에 따라 인덱싱

 

형태에 따라

  • 선형 구조
    • 스택 - LIFO 구조, 먼저 저장된 것이 가장 마지막에 나온다. 파이썬의 리스트 사용
    • - FIFO 구조, 먼저 저장된 것이 제일 먼저 나온다. 파이썬 리스트를 사용해도 되지만, 리스트는 동적 배열로 큐의 연산을 수행하기에 효율적이지 않아 덱을 사용한다.
    • - 양쪽에서 넣고 빼고 할 수 있는 일반화된 선형 구조. 파이썬 deque 사용
      • BFS 문제
  • 비선형 구조
    • 그래프 - 꼭짓점과 꼭짓점을 잇는 변으로 구성된다. 무향 그래프, 유향 그래프가 있다.
    • 트리 - 뿌리와 뿌리 또는 다른 꼭짓점을 단 하나의 부모로 갖는 꼭짓점으로 이루어진 구조. 부모 자식 관계는 간선으로 표시
      • 이진 트리 - 자식이 최대 두개
        • 힙(heap) - 이진트리의 일종으로 최대값과 최소값을 찾아내는 연산을 빠르게 하기 위해 완전 이진트리(complete binary tree) + 힙 속성(property)를 만족한다. 파이썬 heapq 사용 
          • 우선순위 큐(Priority Queue) : 먼저 저장된 데이터가 먼저 나오는 것이 아니라, 우선순위가 높은 순서대로 나가는 형태의 자료구조. 힙을 이용해서 구현한다.
          • 최소값, 최대값 문제
          • 다익스트라 문제
        • heap property : A가 B의 부모노드이면, A의 키 값과 B의 키 값에는 대소관계가 성립한다.

 

스택 문제 - 1874번 스택 수열

https://www.acmicpc.net/problem/1874

 

1874번: 스택 수열

1부터 n까지에 수에 대해 차례로 [push, push, push, push, pop, pop, push, push, pop, push, push, pop, pop, pop, pop, pop] 연산을 수행하면 수열 [4, 3, 6, 8, 7, 5, 2, 1]을 얻을 수 있다.

www.acmicpc.net

#n = 8 # 정수의 개수, 최대 정수값
#arr = [4,3,6,8,7,5,2,1]
n = int(input())
stack = []
maxIdx = 1
answer = []
flag = False

# push 오름차순
for i in range(n):
    x = int(input())
    while maxIdx <= x:
        stack.append(maxIdx)
        answer.append('+')
        maxIdx += 1

    if stack[-1] == x:
        stack.pop()
        answer.append('-')

    else: #stack[-1] != x:
        flag = True
        break


if flag:
    print('NO')
else:
    for x in answer:
        print(x)

 

 

큐 문제 - 1158번 요세푸스 문제

https://www.acmicpc.net/problem/1158

 

1158번: 요세푸스 문제

첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 5,000)

www.acmicpc.net

from collections import deque
# n, k = 7, 3 # 사람 수, 제거하는 사람 위치
n, k = map(int,input().split())
queue = deque() # 덱으로 큐 생성
answer = '<'

# 요소 삽입
for x in range(1, n+1):
    queue.append(x)

while queue:
    for x in range(k-1):
        element = queue.popleft() # 맨 왼쪽에 있는 값 꺼내서
        queue.append(element) # 맨 뒤로 삽입
    answer += str(queue.popleft()) + ', '

print(answer[:-2]+'>')

 

큐 문제 - 1966번 프린터 큐

https://www.acmicpc.net/problem/1966

 

1966번: 프린터 큐

여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 Queue 자료구조에

www.acmicpc.net

from collections import deque

tc = int(input()) # 테스트 케이스 수
for _ in range(tc):
    n, m = map(int, input().split()) # 문서 개수, 찾을 위치
    arr = list(map(int, input().split())) # 문서 중요도 배열
    pq = deque() # 덱으로 큐 생성

    # (인덱스, 중요도) 값으로 덱 요소 삽입
    for x in range(len(arr)):
        pq.append((x, arr[x]))
    importList = sorted(arr, reverse=True)  # 중요도 순서
    importIdx = 0
    cnt = 0
    while pq:
        element = pq.popleft()
        if importList[importIdx] == element[1]:  # 중요도 순서가 맞는 경우
            importIdx += 1
            cnt += 1
            if element[0] == m:  # 찾는 인덱스와 일치할 경우
                print(cnt)
                break
        else:
            pq.append(element)  # 맨 왼쪽 오른쪽에 삽입

 

덱 문제 - 2346번 풍선 터뜨리기

https://www.acmicpc.net/problem/2346

 

2346번: 풍선 터뜨리기

1번부터 N번까지 N개의 풍선이 원형으로 놓여 있고. i번 풍선의 오른쪽에는 i+1번 풍선이 있고, 왼쪽에는 i-1번 풍선이 있다. 단, 1번 풍선의 왼쪽에 N번 풍선이 있고, N번 풍선의 오른쪽에 1번 풍선

www.acmicpc.net

import sys
from collections import deque

n = int(input())
dq = deque(enumerate(map(int, input().split())))
answer = []

while dq:
    idx, nextIdx = dq.popleft()
    answer.append(idx+1)

    if nextIdx > 0:
        dq.rotate(-(nextIdx-1))
    else:
        dq.rotate(-nextIdx) # rotate = d.appendleft(d.pop()) : 오른쪽 끝값을 왼쪽 끝으로 보낸다.

print(*answer)

 

우선순위 큐 문제 - 11286번 절댓값 힙

https://www.acmicpc.net/problem/11286

 

11286번: 절댓값 힙

첫째 줄에 연산의 개수 N(1≤N≤100,000)이 주어진다. 다음 N개의 줄에는 연산에 대한 정보를 나타내는 정수 x가 주어진다. 만약 x가 0이 아니라면 배열에 x라는 값을 넣는(추가하는) 연산이고, x가 0

www.acmicpc.net

import heapq
import sys

n = int(input())  # 연산의 개수 18
# arr = [1, -1, 0, 0, 0, 1, 1, -1, -1, 2, -2, 0, 0, 0, 0, 0, 0, 0]  # 연산에 대한 정보
# 0 x : 배열에서 절댓값이 가장 작은 값 출력하고 값 제거
# 1 x : 값을 넣는 연산
heap = []

for i in range(n):
    x = int(sys.stdin.readline())
    if x != 0:  # 값 넣기
        heapq.heappush(heap, (abs(x), x))
    else:
        # 배열에서 절댓값이 가장 작은 값 출력하고 값 제거
        # 같은 값이 여러개면 가장 작은 수 출력
        # 배열이 비어있으면 0 출력
        if len(heap) == 0:
            print(0)
        else:
            element = heapq.heappop(heap) # heappop : 가장 작은 값 제거 + return
            print(element[1])

 

우선순위 큐 문제 - 1715번 카드 정렬하기

https://www.acmicpc.net/problem/1715

 

1715번: 카드 정렬하기

정렬된 두 묶음의 숫자 카드가 있다고 하자. 각 묶음의 카드의 수를 A, B라 하면 보통 두 묶음을 합쳐서 하나로 만드는 데에는 A+B 번의 비교를 해야 한다. 이를테면, 20장의 숫자 카드 묶음과 30장

www.acmicpc.net

import heapq
n = int(input()) # 숫자 카드 묶음 개수
heap = []
answer = 0

for _ in range(n):
    x = int(input())
    heapq.heappush(heap, x)

while len(heap)!=1:
    a = heapq.heappop(heap)
    b = heapq.heappop(heap)
    answer += a + b
    heapq.heappush(heap, a+b)

print(answer)

 

해시(Hash)

  • 데이터를 다루는 방법 중 하나로, O(N) 시간 복잡도를 가진 연산을 O(1) 시간 복잡도로 해결할 수 있다.
  • key-value 형태로 데이터가 저장된다.

 

 

해시 함수(Hash function)

  • 임의의 길이를 갖는 임의의 데이터를 고정되 길이의 데이터로 매핑하는 단방향 함수
  • 해시 값 : 해시 함수를 적용하여 나온 값, 해시 코드, 해시섬(sum), 체크섬 등으로 불린다.
  • 해시 충돌(hash collision) : 서로 다른 키가 같은 해시가 되는 경우 

 

해시 테이블(Hash Table)

  • 연관 배열 구조(associative array)를 사용해서 데이터를 key, value으로 저장하는 자료구조
    • 연관 배열 구조 : 키 1개와 값 1개가 1:1으로 연관되어 있는 자료구조

 

딕셔너리(Dictionary)

  • dictionary는 해시 테이블(hash table)

 


Set

- 순서가 없는 데이터의 집합

- 중복 허용 X

- HashSet, TreeSet

 

 

Map

- key, value가 한 쌍으로 이루어지는 데이터의 집합

- 순서가 없는 데이터의 집합

- key 중복 허용 X, value는 중복 허용

- HashMap, TreeMap, Hashtable, Properties

 

Set Map
value key : value
값 중복 X key 중복 X, value 허용
contains(value) containsKey(key)
get 불가능 get(key)

 

Hash

- 순서가 없다.

 

 

Tree

- 트리 구조로, 순서 유지

 

Hash Tree
순서 없음 순서 유지
O(1) O(log n)

 

HashMap vs HashSet vs TreeMap vs TreeSet

HashMap HashSet TreeMap TreeSet
key 중복 X value 허용 value 중복 X key 중복X value 허용 value 중복X
순서 없음 순서 없음 순서 유지 순서 유지

 

 

 

해시 문제 - 7785번 회사에 있는 사람

https://www.acmicpc.net/problem/7785

 

7785번: 회사에 있는 사람

첫째 줄에 로그에 기록된 출입 기록의 수 n이 주어진다. (2 ≤ n ≤ 106) 다음 n개의 줄에는 출입 기록이 순서대로 주어지며, 각 사람의 이름이 주어지고 "enter"나 "leave"가 주어진다. "enter"인 경우는

www.acmicpc.net

 

from collections import defaultdict
#n = 4 # 출입 기록 수
# arr = ['Baha enter', 'Askar enter', 'Baha leave', 'Artem enter']

# enter 출근, leave 퇴근
# 대소문자 구분
# 현재 회사에 있는 모든 사람을 구하는 프로그램 작성
n = int(input())
dict = defaultdict(str)

for x in range(n):
    name, opt = input().split()
    if dict[name] == 'enter' and opt == 'leave':
        del dict[name]
    else:
        dict[name] = opt

for x in sorted(dict.keys(),reverse=True):
    print(x)

 

 

해시 문제 - 14425번 문자열 집합

https://www.acmicpc.net/problem/14425

from collections import defaultdict
n, m = map(int, input().split())
answer = 0
S = defaultdict(int)
for x in range(n):
    key = input()
    S[key] = 1

for x in range(m):
    key = input()
    if S[key]:
        answer += 1
print(answer)

투포인터

  • 배열에서 이중 for문으로 O(N^2) 시간복잡도를 가진 탐색을 하는 문제에서 포인터 2개를 사용해 O(N)으로 해결하는 알고리즘

 

슬라이딩 윈도우(Sliding Window)

  • 투 포인터와 비슷하지만, 고정 사이즈의 윈도우를 이동시키는 알고리즘
  • 정렬된 배열이 아니여도 사용 가능

 

구간합(prefix sum)

  • 수열에서 특정 구간의 합
  • i ~ j 번째 인덱스 값들의 값

 

부분합(partial sum)

  • 0 ~ n 번째 인덱스 값들의 합

 

누적합(prefix)

  • 수열의 특정 구간의 값을 구하는 요청이 여러개인 경우 시간 복잡도를 O(N^2)에서 O(N)으로 줄이기 위해 사용된다.

 

누적합의 성질

  • 1차원 배열 공간 복잡도는 O(n), 2차원의 공간 복잡도 O(n^2)
  • 계산은 O(1) 시간 복잡도
  • 합을 구하는 도중에 배열의 값이 변경되면 세그먼트 트리 사용
sumArr[0] = arr[0]
sumArr[i] = sumArr[i-1] + arr[i]
sumArr[n] = arr[0] + arr[1] + ... + arr[n-1] + arr[n]
sumArr[j]-sumArr[i] = arr[i] + arr[i+1] + ... + arr[j-1] + arr[j]

 

누적합 문제 예시 - 1차원 배열

  • index 3~5의 값
    • arr[3] + arr[4] + arr[5] = 6 + 10 + 3 = 19
    • sumArr[5] - sumArr[2] = 31 - 12 = 19 
index 0 1 2 3 4 5
배열 arr 3 5 4 6 10 3
누적합 sumArr 3 8 12 18 28 31

 

누적합 문제 예시 - 2차원 배열

  • 2차원 배열
index 0 1 2 3 4
0 3 5 4 3 4
1 5 7 10 5 7
2 3 3 6 6 8
3 6 6 8 9 4
4 5 2 7 3 5
  • 첫 번째로 행끼리 누적합을 구해준다.
index 0 1 2 3 4
0 3 8 12 15 19
1 5 12 22 27 34
2 3 6 12 18 26
3 6 12 20 29 33
4 5 7 14 17 22
  • 두 번째로 열끼리 누적합을 구해준다.
index 0 1 2 3 4
0 3 8 12 15 19
1 8 20 34 42 53
2 11 26 46 60 79
3 17 38 66 89 112
4 22 45 80 106 134

 

  • (3,3)에서 (4,4) 노란색 부분의 합을 구하려고 할 때
  • sumArr[x2][y2] - sumArr[x2][y-1] - sumArr[x1][y2] + sumArr[x1-1][y1-1]
  • sumArr[4][4](전체) - sumArr[4][2](초록색) - sumArr[2][4](파란색) + sumArr[2][2] = 노란색 구역의 합
  • 빨간색 영역은 초록색과 파란색 영역의 누적합을 뺄 때 제거된다. 
  • 두 영역에서 빨간색 영역을 두 번 빼줬기 때문에 한 번 더해준다.


투포인터 문제 - 2230번 수 고르기

https://www.acmicpc.net/problem/2230

 

2230번: 수 고르기

N개의 정수로 이루어진 수열 A[1], A[2], …, A[N]이 있다. 이 수열에서 두 수를 골랐을 때(같은 수일 수도 있다), 그 차이가 M 이상이면서 제일 작은 경우를 구하는 프로그램을 작성하시오. 예를 들어

www.acmicpc.net

 

n, m = 5, 3  # 정수 개수, 두 개의 정수 차이 최소 기준
arr = [1, 2, 3, 4, 5]
#n, m = map(int, input().split())
#arr = [int(input()) for _ in range(n)]
arr.sort()
lt = 0
rt = 0
minValue = float('inf')
# print(arr)
while rt != n and lt <= rt:
    value = arr[rt] - arr[lt]
    if value >= m:  # m 이상일 때
        minValue = min(minValue, value)
        lt += 1
    else:  # m 이상이 아닐 때
        rt += 1
print(minValue)

 

투포인터 문제 - 1806번 부분합

https://www.acmicpc.net/problem/1806

 

1806번: 부분합

첫째 줄에 N (10 ≤ N < 100,000)과 S (0 < S ≤ 100,000,000)가 주어진다. 둘째 줄에는 수열이 주어진다. 수열의 각 원소는 공백으로 구분되어져 있으며, 10,000이하의 자연수이다.

www.acmicpc.net

 

#n, s = 10, 15
#arr = [5, 1, 3, 5, 10, 7, 4, 9, 2, 8]
n, s = map(int,input().split())
arr = list(map(int,input().split()))

lt = 0
rt = 0
minLen = float('inf')
value = 0

while True:
    # 수들의 합이 s를 넘으면 최소값을 계산
    # 안넘으면 rt 값 증가
    if value >= s:
        minLen = min(minLen, (rt - lt))
        value -= arr[lt]
        lt += 1
    elif rt == n:
        break
    else: # value < s:
        value += arr[rt]
        rt += 1

if minLen == float('inf'):
    minLen = 0

print(minLen)

 

누적합 문제 - 11660번 구간 합 구하기 5

https://www.acmicpc.net/problem/11660

 

11660번: 구간 합 구하기 5

첫째 줄에 표의 크기 N과 합을 구해야 하는 횟수 M이 주어진다. (1 ≤ N ≤ 1024, 1 ≤ M ≤ 100,000) 둘째 줄부터 N개의 줄에는 표에 채워져 있는 수가 1행부터 차례대로 주어진다. 다음 M개의 줄에는 네

www.acmicpc.net

 

import sys
# n, m = 4, 3 # 표의 크기, 연산 횟수
n, m = map(int, input().split())
arr = [[0]*(n+1)] + list([0]+list(map(int, input().split())) for _ in range(n))
sumArr = [[0]*(n+1) for _ in range(n+1)]

# 누적합 배열 만들기
for i in range(1, n+1):
    for j in range(1, n+1):
        sumArr[i][j] = sumArr[i-1][j] + sumArr[i][j-1] - sumArr[i-1][j-1] + arr[i][j]

# 계산 하기 - (x1, y1) 부터 (x2, y2) 합 구하기
# 전체 - 영역1 - 영역2 + (영역1과 영역2에서 두번 빼줬기 때문에 더해줘야 하는 영역)
for _ in range(m):
    x1, y1, x2, y2 = map(int, sys.stdin.readline().split())
    res = sumArr[x2][y2] - sumArr[x1-1][y2] - sumArr[x2][y1-1] + sumArr[x1-1][y1-1]
    print(res)

그리디(Greedy)

  • 현재 상황에서 가장 최적의 답을 선택하는 알고리즘
  • 최종적으로 최적의 해가 나온다는 보장이 없다.
  • 탐욕 선택 속성(greedy choice property), 최적 부분 구조(optimal substructure) 특성의 문제에 적합하다.
    • 최적 부분 구조 예시 : (서울과 대구의 최단 경로) + (대구와 부산의 최단 경로) = 서울과 부산의 최단 경로
  • 한 번의 선택이 다음 선택에 무관해야 하고, 매 순간의 최적해가 문제에 대한 최적해여야 한다.
  • 활용 예시
    • 거스름돈, 다익스트라 알고리즘, 허프만 코드, 크루스칼 알고리즘

 

그리디 문제 - 11047번 동전 0

https://www.acmicpc.net/problem/11047

 

11047번: 동전 0

첫째 줄에 N과 K가 주어진다. (1 ≤ N ≤ 10, 1 ≤ K ≤ 100,000,000) 둘째 줄부터 N개의 줄에 동전의 가치 Ai가 오름차순으로 주어진다. (1 ≤ Ai ≤ 1,000,000, A1 = 1, i ≥ 2인 경우에 Ai는 Ai-1의 배수)

www.acmicpc.net

 

# n, k = 10, 4200  # 동전 종류, 구하려는 값 - 동전의 최소 개수 구하기
# arr = [1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 50000]
n, k = map(int, input().split())
arr = []
for _ in range(n):
    arr.append(int(input()))
arr = sorted(arr, reverse=True)
cnt = res = 0

for x in arr:
    if k >= x:
        cnt = k // x
        res += cnt
        k = k - (x * cnt)
    if k <= 0:
        break
print(res)

 

그리디 문제 - 1931번 회의실 배정

- 최대 회의 횟수 구하기

https://www.acmicpc.net/problem/1931

 

1931번: 회의실 배정

(1,4), (5,7), (8,11), (12,14) 를 이용할 수 있다.

www.acmicpc.net

n = int(input())  # 회의 수 - 회의가 겹치지 않게 진행할 수 있는 회의 최대 개수 구하기
arr = [[0] * 2 for _ in range(n)]
for i in range(n):
    a, b = map(int, input().split())
    arr[i][0] = a # 회의 시작 시간
    arr[i][1] = b # 회의 끝나는 시간

#n = 11
#arr = [[1, 1], [1, 5], [0, 6], [5, 7], [3, 8], [5, 9], [6, 10], [8, 11], [8, 12], [2, 13], [12, 14]]
#n = 3
#arr = [[1,1],[1,1],[0,1]]
arr.sort(key=lambda x: (x[1], x[0])) # 두번째 값이 같은 경우, 첫번째 값으로 오름차순
time = cnt = start = end = 0

for element in arr:
    start = element[0]
    end = element[1]
    if time <= start:
        time = end
        cnt += 1
print(cnt)

 

그리디 문제 - 11000번 강의실 배정

- 최소 강의실 개수 구하기

https://www.acmicpc.net/problem/11000

 

11000번: 강의실 배정

첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000) 이후 N개의 줄에 Si, Ti가 주어진다. (0 ≤ Si < Ti ≤ 109)

www.acmicpc.net

# 최소 강의실 개수 구하기
import heapq
import sys

input = sys.stdin.readline
N = int(input())  # 수업의 개수

class_list = []

for _ in range(N):
    x, y = map(int, input().split())
    class_list.append([x, y])

class_list.sort()
heap = []
heapq.heappush(heap, class_list[0][1])  # 첫 번째 강의 끝나는 시간
# heap 최소 힙 유지 = 0 번째 인덱스는 가장 작은 값

for idx in range(1, N):
    start, end = class_list[idx]
    if start < heap[0]: # 빠른 시작 시간 < 앞에서 가장 빨리 끝나는 값
        heapq.heappush(heap, end) # 새 강의실 추가
    else: # 강의실 유지, 강의 시간 갱신
        heapq.heappop(heap)
        heapq.heappush(heap, end)
print(len(heap))

 

 

그리디 문제 - 2217번 로프

https://www.acmicpc.net/problem/2217

 

2217번: 로프

N(1 ≤ N ≤ 100,000)개의 로프가 있다. 이 로프를 이용하여 이런 저런 물체를 들어올릴 수 있다. 각각의 로프는 그 굵기나 길이가 다르기 때문에 들 수 있는 물체의 중량이 서로 다를 수도 있다. 하

www.acmicpc.net

 

# n = 2  # 로프의 개수
# arr = [10, 15]  # 로프가 버틸 수 있는 최대 중량
n = int(input())
arr = []
for _ in range(n):
    arr.append(int(input()))
arr = sorted(arr, reverse=True)
maxRes = 0

# 내림차순으로 들을 수 있는 로프 개수 * 현재 무게를 계산해서 최대값을 구해준다.
for k in range(n):
    maxRes = max(arr[k]*(k+1), maxRes)
print(maxRes)

 

그리디 문제 - 1026번 보물

https://www.acmicpc.net/problem/1026

 

1026번: 보물

첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거

www.acmicpc.net

 

# n = 5  # 정수의 개수
# arrA = [1, 1, 1, 6, 0]  # A 정수 배열
# arrB = [2, 7, 8, 3, 1]  # B 정수 배열

n = int(input())
arrA = list(map(int, input().split()))
arrB = list(map(int, input().split()))

# S = A[0] * B[0] + A[1] * B[1] + ...+ A[N-1] * B[N-1]
# 계산 값을 가장 작게 만들기 위해서는 각 배열을 오름차순, 내림차순 해준다.
arrA.sort()
arrB.sort(reverse=True)
res = 0

for x in range(n):
    res += arrA[x]*arrB[x]

print(res)

 

그리디 문제 - 8980번 택배

https://www.acmicpc.net/problem/8980

 

8980번: 택배

입력의 첫 줄은 마을 수 N과 트럭의 용량 C가 빈칸을 사이에 두고 주어진다. N은 2이상 2,000이하 정수이고, C는 1이상 10,000이하 정수이다. 다음 줄에, 보내는 박스 정보의 개수 M이 주어진다. M은 1이

www.acmicpc.net

 

# 트럭 한 대로 배송할 수 있는 최대 박스 수 출력
N, C = map(int, input().split())  # 마을의 수, 트럭 용량
M = int(input())  # 박스 정보 개수
info = []
res = 0

for _ in range(M):
    # 박스를 보내는 마을, 박스를 받는 마을, 보내는 박스의 개수
    from_box, to_box, num_box = map(int, input().split())
    info.append((from_box, to_box, num_box))

sort_info = sorted(info, key=lambda x: x[1]) # 가장 빨리 받는 순서대로 정렬
remain = [0] * (N+1) # 남은 상자

for item in sort_info:
    start, end, box = item[0], item[1], item[2]
    max_box = box
    for i in range(start, end): # 시작점부터 도착지까지 보낼 수 있는 박스 개수
        max_box = min(max_box, C - remain[i])
    # print(max_box, C-remain[i])
    for j in range(start, end):
        remain[j] += max_box
    res += max_box
print(res)

https://hhiyeon.tistory.com/252

 

[백준] 1541번 잃어버린 괄호

https://www.acmicpc.net/problem/1541 1541번: 잃어버린 괄호 첫째 줄에 식이 주어진다. 식은 ‘0’~‘9’, ‘+’, 그리고 ‘-’만으로 이루어져 있고, 가장 처음과 마지막 문자는 숫자이다. 그리고 연속해서

hhiyeon.tistory.com

 

https://hhiyeon.tistory.com/253

 

[백준] 11501번 주식

https://www.acmicpc.net/problem/11501 11501번: 주식 입력의 첫 줄에는 테스트케이스 수를 나타내는 자연수 T가 주어진다. 각 테스트케이스 별로 첫 줄에는 날의 수를 나타내는 자연수 N(2 ≤ N ≤ 1,000,000)이

hhiyeon.tistory.com

 

https://hhiyeon.tistory.com/254

 

[백준] 2170번 선긋기

https://www.acmicpc.net/problem/2170 2170번: 선 긋기 첫째 줄에 선을 그은 횟수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 다음 N개의 줄에는 선을 그을 때 선택한 두 점의 위치 x, y (-1,000,000,000 ≤ x < y ≤ 1,000,000,000)

hhiyeon.tistory.com

 

https://hhiyeon.tistory.com/255

 

[백준] 1744번 수묶기

https://www.acmicpc.net/problem/1744 1744번: 수 묶기 길이가 N인 수열이 주어졌을 때, 그 수열의 합을 구하려고 한다. 하지만, 그냥 그 수열의 합을 모두 더해서 구하는 것이 아니라, 수열의 두 수를 묶으려

hhiyeon.tistory.com

 

이분 탐색(binary search)

  • 순차 탐색 O(n)의 시간 복잡도를 O(logn)으로 줄일 수 있다.
  • 오름차순으로 정렬된 정수의 리스트에서 특정 데이터를 찾기 위해 탐색 범위를 절반으로 좁혀가면서 탐색하는 방법

 

이분 탐색 문제 - 1920번 수 찾기 

https://www.acmicpc.net/problem/1920

 

1920번: 수 찾기

첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들

www.acmicpc.net

 

n = 5
a = [4, 1, 5, 2, 3]
m = 5
b = [1, 3, 7, 9, 5]
a = sorted(a)
maxVal = a[-1] # 최대값

for element in b:
    lt = 0
    rt = n - 1
    res = 0

	# 최대값보다 구해야하는 수가 작은 경우만 이분 탐색
    if maxVal >= element:
        while lt <= rt:
            mid = (lt + rt) // 2
            print(element, lt, rt, mid, a[mid], res)
            if a[mid] == element:
                res = 1
                break
            elif a[mid] < element:
                lt = mid +1
            else:
                rt = mid -1
    print(res)

 

이분 탐색 문제 - 1654번 랜선 자르기

https://www.acmicpc.net/problem/1654

 

1654번: 랜선 자르기

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그

www.acmicpc.net

 

# k, n = 4, 11  # 이미 가지고 있는 랜선 개수, 필요한 랜선 개수 n
# kArr = [802, 743, 457, 539] # 랜선은 길이가 모두 다르다.
k, n = map(int, input().split())
kArr = []

for i in range(k):
    kArr.append(int(input()))
kArr = sorted(kArr) # 이분 탐색을 위한 정렬
lt = 0
rt = kArr[-1]
maxLen = 0

while lt <= rt:
    mid = (lt+rt)//2
    total = 0
    for size in kArr: # 구할 수 있는 랜선 개수 구하기
        total += (size//mid)

    if total >= n: # 랜선의 개수가 더 많을 경우
        maxLen = max(maxLen, mid) # 최대값 갱신
        lt = mid +1
    else:
        rt = mid -1 # 랜선의 개수가 부족할 경우 
print(maxLen)

 

이분 탐색 문제 - 2110번 공유기 설치

https://www.acmicpc.net/problem/2110

 

2110번: 공유기 설치

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가

www.acmicpc.net

import sys

n, c = map(int, sys.stdin.readline().split())  # 집의 개수, 공유기 개수
x_arr = []

for _ in range(n):
    x = int(sys.stdin.readline())  # 집의 좌표
    x_arr.append(x)

x_arr.sort()

res = 0
start = 1  # 최소 거리 1
end = x_arr[-1] - x_arr[0]  # 최대 거리 = 가장 먼거리

while start <= end:
    mid = (start + end) // 2  # 중간값 = 현재 가능한 공유기 사이의 거리
    temp = x_arr[0]  # 이전 집의 좌표
    cnt = 1

    for i in range(1, n):
        if x_arr[i] - temp >= mid:  # 가능한 거리(mid) 이상으로 공유기를 설치할 수 있는 집에 공유기 설치
            cnt += 1
            temp = x_arr[i]

    if cnt >= c:  # c개 이상의 공유기를 설치할 수 있는지 확인
        start = mid + 1  # 가능하면 mid 증가
        res = mid
    else:
        end = mid - 1  # 불가능하면 mid 감소

print(res)

https://www.acmicpc.net/problem/11053

 

11053번: 가장 긴 증가하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이

www.acmicpc.net

 

LIS 알고리즘 - DP

https://hhiyeon.tistory.com/167

 

[알고리즘] LIS(Longest Increasing Subsequence) 최장 증가 부분 수열

LIS 알고리즘 최장 증가 부분 수열 일반적으로 DP(동적 계획법)으로 푸는 알고리즘 임의의 수열이 주어질 때, 이 숭려에서 몇 개의 수들을 제거해서 부분 수열을 만든다. 이 때 부분수열들을 오름

hhiyeon.tistory.com

 

 

백준 풀이

#n = 6
#arr = [10,20,10,30,20,50]
n = int(input())
arr = list(map(int, input().split()))
dp = [1]*n # 리스트로 반복되는 횟수를 저장한다.
for i in range(n):
	for j in range(i):
		if arr[i] > arr[j]:
			dp[i] = max(dp[i], dp[j]+1)

# print(dp)
# 1 2 1 3 2 4
# 10의 길이 1, 20의 길이 2, 10의 길이 ...
print(max(dp))

+ Recent posts