250x250
Notice
Recent Posts
Recent Comments
Link
상봉동개발자
[백준] 1753, 1654, 1012, 2206 본문
728x90
최단경로 (1753번)
- 사이트/난이도: 백준 / 골드4
- 코드
# 골드4 최단경로
import sys
import heapq
input = sys.stdin.readline
v, e = map(int, input().split())
k = int(input())
INF = int(1e9)
distance = [INF] * (v+1)
graph = [[] for _ in range(v+1)]
for _ in range(e):
a, b, c = map(int, input().split())
graph[a].append((b,c))
def dijkstra(start):
q = []
heapq.heappush(q, (0, start))
distance[start] = 0
while q:
dist, now = heapq.heappop(q)
if distance[now] < dist:
continue
for i in graph[now]:
cost = dist + i[1]
if distance[i[0]] > cost:
distance[i[0]] = cost
heapq.heappush(q, (cost, i[0]))
dijkstra(k)
for i in range(1, v+1):
if distance[i] == INF:
print("INF")
else:
print(distance[i])
- 느낀점
- 다익스트라 알고리즘 문제
- 정점과 간선개수가 2만, 30만이므로 시간복잡도가 $O(ElogV)$ (E: 간선, V: 노드) 인 우선순위 큐를 이용하는 다익스트라 알고리즘을 사용해야된다.
- 다익스트라 알고리즘
- 특정한 노드에서 다른 모든 노드로 가는 최단 경로
- 음의 간선이 없을 때 정상 동작
- 매 상황에서 가장 비용이 적은 노드 선택 (그리디 알고리즘으로 분류)
- 동작 과정
- 출발 노드 설정
- 최단 거리 테이블 초기화 (무한으로)
- 방문하지 않은 노드 중에서 최단거리가 가장 짧은 노드 선택
- 해당 노드를 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블 갱신
- 3, 4번 반복
랜선 자르기 (1654번)
- 사이트/난이도: 백준 / 실버2
- 코드
# 실버2 랜선 자르기
import sys
input = sys.stdin.readline
k, n = map(int, input().split())
lengths = []
for _ in range(k):
lengths.append(int(input()))
def get_count(mid):
count = 0
for l in lengths:
count += l // mid
return count
def binary_search(start, end):
while start <= end:
mid = (start + end) // 2
print(start, end, mid)
result = get_count(mid)
if result >= n: # 자른 개수가 더 많으면 -> 크게 잘라야함
start = mid + 1
else:
end = mid - 1
return end
print(binary_search(1, max(lengths)))
- 느낀점
- 랜선의 길이와 n, k범위가 엄청 크므로 logN의 시간복잡도를 가지는 이진탐색을 이용해야한다.
- 여기서 헤멨던게 최대 랜선 길이를 가져야 하므로 해당 랜선 개수를 만족하는 mid를 가지고 끝내는게 아닌 해당 랜선 개수 이상일 때 계속 반복하면서 최대 길이인 end를 반환해야 한다.
- 아래 블로그에서 자세하게 설명해준다.
- https://velog.io/@ledcost/백준-1654-파이썬-랜선-자르기-실버3-이분-탐색
유기농 배추 (1012번)
- 사이트/난이도: 백준/실버2
- 코드
# 실버2 유기농 배추
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10000)
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
def dfs(x, y):
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < n and 0 <= ny < m:
if graph[nx][ny] == 1:
graph[nx][ny] = -1
dfs(nx,ny)
t = int(input())
for _ in range(t):
m, n, k = map(int, input().split())
graph = [[0] * m for _ in range(n)]
for _ in range(k):
y, x = map(int, input().split())
graph[x][y] = 1
answer = 0
for i in range(n):
for j in range(m):
if graph[i][j] == 1:
dfs(i, j)
answer += 1
print(answer)
- 느낀점
- 기본적인 dfs 문제
- 최대 재귀 한도인 sys.setrecursionlimit(10000) 을 처음에 설정 안해서 런타임에러로 실패했음
벽 부수고 이동하기 (2206번)
- 사이트/난이도: 백준/골드4
- 코드
# 골드4 벽 부수고 이동하기
from collections import deque
n, m = map(int, input().split())
graph = [list(map(int, input())) for _ in range(n)]
# 3차원 행렬 visited[x][y][z] => z = 0 이라면 벽 파괴 가능 / z = 1 이라면 벽 한번 뚫은 상태
# 중간에 벽을 부순 경로는 벽을 안부순 경로만 이동 가능, 벽을 안부순 경로는 그 이후 벽을 한번 부술 경로로 이동 가능
visited = [[[0] * 2 for _ in range(m)] for _ in range(n)]
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
def bfs():
q = deque([])
q.append((0, 0, 0))
visited[0][0][0] = 1
while q:
x, y, z = q.popleft()
if x == n-1 and y == m-1:
return visited[x][y][z]
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < n and 0 <= ny < m:
if graph[nx][ny] == 0 and visited[nx][ny][z] == 0: # 벽이 아니고 한번도 방문 안했다면
visited[nx][ny][z] = visited[x][y][z] + 1
q.append((nx, ny, z))
elif graph[nx][ny] == 1 and z == 0: # 벽이고 아직 벽 파괴를 사용하지 않았다면
visited[nx][ny][1] = visited[x][y][z] + 1
q.appendleft((nx, ny, 1))
return -1
print(bfs())
- 느낀점
- 기본적인 bfs + 벽 부수는 응용 문제
- 벽 부수는 것을 visited에 3차원 배열로 해서 표시해준다.
- 처음에 접근할 떄는 그냥 큐에다가 부쉈는지 안부쉈는지를 표시해주는 변수 하나만 더 추가해줬는데 이렇게 해서 graph에다가만 방문표시 해주면 임의의 x,y 좌표에서 벽 부수고 온 경로와 벽 안부수고 온 경로가 혼합되어 오류가 난다..
- 그러므로 3차원 배열로 벽 안부수고 온 경로는 이후에 벽을 부술수 있는 경로로 이동할 수 있게 하고, 벽을 부수고 온 경로는 벽 안부수는 경로로만 가게하여 최단거리를 구한다.
- 아래 블로그를 참고했다.
- https://hongcoding.tistory.com/18
728x90
'코테준비' 카테고리의 다른 글
| [백준] 2468 (0) | 2022.11.05 |
|---|---|
| [백준] 1744, 11000 (0) | 2022.11.04 |
| [백준] 16926, 1946, 1715, 16953 (0) | 2022.11.01 |
| [백준] 13913, 14226, 13549 (0) | 2022.10.30 |
| [백준] 7562, 1697 (0) | 2022.10.29 |
Comments