728x90

문제

방향그래프가 주어지면 주어진 시작점에서 다른 모든 정점으로의 최단 경로를 구하는 프로그램을 작성하시오. 단, 모든 간선의 가중치는 10 이하의 자연수이다.

입력

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 ≤ K ≤ V)가 주어진다. 셋째 줄부터 E개의 줄에 걸쳐 각 간선을 나타내는 세 개의 정수 (u, v, w)가 순서대로 주어진다. 이는 u에서 v로 가는 가중치 w인 간선이 존재한다는 뜻이다. u와 v는 서로 다르며 w는 10 이하의 자연수이다. 서로 다른 두 정점 사이에 여러 개의 간선이 존재할 수도 있음에 유의한다.

출력

첫째 줄부터 V개의 줄에 걸쳐, i번째 줄에 i번 정점으로의 최단 경로의 경로값을 출력한다. 시작점 자신은 0으로 출력하고, 경로가 존재하지 않는 경우에는 INF를 출력하면 된다.

코드

import heapq
import sys
input = sys.stdin.readline
INF = int(1e9)

n,m = map(int,input().split()) #간선, 노드
start = int(input()) #시작노드
#각 노드에 연결되어 있는 노드에 대한 정보 리스트
graph = [[] for _ in range(n+1)]
distance = [INF]*(n+1)
for _ in range(m):
    a,b,c = map(int,input().split())
    graph[a].append((b,c))  #노드 a에서 노드 b로 가는 비용이 c라는 의미

#다익스트라
def dijkstra(start):
    q = []
    heapq.heappush(q,(0,start))
    distance[start] = 0
    while q:
        #우선순위 큐에서 가장 최단 거리가 짧은 노드 꺼내기
        dist,node = heapq.heappop(q)
        #현재 노드가 이미 처리된 노드면 무시
        if distance[node] < dist:
            continue
        #현재 노드와 연결된 다른 인접한 노드들 확인
        for i in graph[node]:
            #현재 노드를 거쳐서 다른 노드로 이동하는 거리
            cost = dist + i[1]
            if cost < distance[i[0]]:
                distance[i[0]] = cost
                heapq.heappush(q,(cost,i[0]))
dijkstra(start)

#모든 노드로 가는 최단거리 출력
for i in range(1,n+1):
    if distance[i] == INF:
        print("INF")
    else:
        print(distance[i])

풀이

최단경로 다익스트라 알고리즘이다.

다익스트라 알고리즘은 그리디 알고리즘에 속한다.

우선순위 큐를 사용해 출발 노드의 인근 노드의 최소 비용을 구해 최단 거리로 이동한다.

python에서의 우선순위 큐는 heapq 라이브러리를 사용해 구현한다.

heapq는 최소힙이 디폴트다.

728x90

문제

땅 위에 달팽이가 있다. 이 달팽이는 높이가 V미터인 나무 막대를 올라갈 것이다.

달팽이는 낮에 A미터 올라갈 수 있다. 하지만, 밤에 잠을 자는 동안 B미터 미끄러진다. 또, 정상에 올라간 후에는 미끄러지지 않는다.

달팽이가 나무 막대를 모두 올라가려면, 며칠이 걸리는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 세 정수 A, B, V가 공백으로 구분되어서 주어진다. (1 ≤ B < A ≤ V ≤ 1,000,000,000)

출력

첫째 줄에 달팽이가 나무 막대를 모두 올라가는데 며칠이 걸리는지 출력한다.

코드 ( 시간초과 )

import sys

a,b,v = map(int,sys.stdin.readline().split())
day = 0
h = 0
while True:
    day += 1
    h += a
    if h == v:
        print(day)
        break
    h -= b

코드 

import sys
import math
a,b,v = map(int,sys.stdin.readline().split())

day = (v-b)/(a-b)
print(math.ceil(day))

풀이

(a-b) 씩 day가 증가하고 day == v 가 됐을 때가 정답이다.

하지만, 정상에 오르면 밤에 미끄러지지 않기 때문에, 

v / (a-b) 가 아니고 (v-b) / (a-b) 이다.

'알고리즘 문제 풀이 > 백준' 카테고리의 다른 글

[백준] 2512 예산 python  (0) 2022.03.05
[백준] 1753 최단경로 python  (0) 2022.03.04
[백준] 1654 랜선 자르기 python  (0) 2022.03.03
[백준] 1149 RGB거리 python  (0) 2022.03.02
[백준] 2293 동전 1 python (*)  (0) 2022.03.01
728x90

문제

집에서 시간을 보내던 오영식은 박성원의 부름을 받고 급히 달려왔다. 박성원이 캠프 때 쓸 N개의 랜선을 만들어야 하는데 너무 바빠서 영식이에게 도움을 청했다.

이미 오영식은 자체적으로 K개의 랜선을 가지고 있다. 그러나 K개의 랜선은 길이가 제각각이다. 박성원은 랜선을 모두 N개의 같은 길이의 랜선으로 만들고 싶었기 때문에 K개의 랜선을 잘라서 만들어야 한다. 예를 들어 300cm 짜리 랜선에서 140cm 짜리 랜선을 두 개 잘라내면 20cm는 버려야 한다. (이미 자른 랜선은 붙일 수 없다.)

편의를 위해 랜선을 자르거나 만들 때 손실되는 길이는 없다고 가정하며, 기존의 K개의 랜선으로 N개의 랜선을 만들 수 없는 경우는 없다고 가정하자. 그리고 자를 때는 항상 센티미터 단위로 정수길이만큼 자른다고 가정하자. N개보다 많이 만드는 것도 N개를 만드는 것에 포함된다. 이때 만들 수 있는 최대 랜선의 길이를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그 후 K줄에 걸쳐 이미 가지고 있는 각 랜선의 길이가 센티미터 단위의 정수로 입력된다. 랜선의 길이는 231-1보다 작거나 같은 자연수이다.

출력

첫째 줄에 N개를 만들 수 있는 랜선의 최대 길이를 센티미터 단위의 정수로 출력한다.

코드

import sys
k,n = map(int,sys.stdin.readline().split())
arr = []
for i in range(k):
    arr.append(int(sys.stdin.readline()))
start = 1
end = max(arr)
while (start<=end):
    total = 0
    mid = (start+end)//2
    for i in arr:
        total += i//mid
    if total >= n:
        start = mid + 1
    else:
        end = mid -1
print(end)

풀이

파라메트릭 서치 ( Parametric Search)

: 최적화 문제를 결정 문제( yes or no)로 바꾸어 해결하는 기법

: 원하는 조건을 만족하는 가장 알맞은 값을 찾는 문제

 

-> 이분 탐색 방법으로 푼다. ( 재귀 말고 반복문 사용 )

start = 1

end = max(arr)

mid = (start + end)//2

start가 end가 될 때까지, mid값을 조절하여 답(end값)을 구한다.

 

 

728x90

문제

RGB거리에는 집이 N개 있다. 거리는 선분으로 나타낼 수 있고, 1번 집부터 N번 집이 순서대로 있다.

집은 빨강, 초록, 파랑 중 하나의 색으로 칠해야 한다. 각각의 집을 빨강, 초록, 파랑으로 칠하는 비용이 주어졌을 때, 아래 규칙을 만족하면서 모든 집을 칠하는 비용의 최솟값을 구해보자.

  • 1번 집의 색은 2번 집의 색과 같지 않아야 한다.
  • N번 집의 색은 N-1번 집의 색과 같지 않아야 한다.
  • i(2 ≤ i ≤ N-1)번 집의 색은 i-1번, i+1번 집의 색과 같지 않아야 한다.

입력

첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 모든 집을 칠하는 비용의 최솟값을 출력한다.

코드

import sys
n = int(sys.stdin.readline())
rgb = []
for _ in range(n):
    rgb.append(list(map(int,sys.stdin.readline().split())))

for i in range(1,n):
    #R
    rgb[i][0] = min(rgb[i-1][1], rgb[i-1][2]) + rgb[i][0]
    #G
    rgb[i][1] = min(rgb[i-1][0], rgb[i-1][2]) + rgb[i][1]
    #B
    rgb[i][2] = min(rgb[i-1][0], rgb[i-1][1]) + rgb[i][2]
print(min(rgb[n-1]))

풀이

빨강, 초록, 파랑 순으로 집 비용이 있다.

조건을 따지고 보면 전 집의 색을 제외한 다른 색 중 가장 작은 비용의 색으로 칠하면 된다.

 

index 가 0은 제외하고

1부터 반복문을 색별로 돌면 된다.

#R
rgb[i][0] = min(rgb[i-1][1], rgb[i-1][2]) + rgb[i][0]

설명해보면, i가 1이라고 해보자.

rgb[1][0] 1번집의 빨간색으로 칠하는 비용은, 전 집인 0번째 집은 빨간색으로 칠하면 안된다. 

0번째 집의 비용은 초록 rgb[0][1], 파랑 rgb[0][2] 중 작은 비용을 선택하고 현재 1번집의 빨간색 비용을 더한 값이 rgb[1][0] 이 되겠다.

728x90

문제

n가지 종류의 동전이 있다. 각각의 동전이 나타내는 가치는 다르다. 이 동전을 적당히 사용해서, 그 가치의 합이 k원이 되도록 하고 싶다. 그 경우의 수를 구하시오. 각각의 동전은 몇 개라도 사용할 수 있다.

사용한 동전의 구성이 같은데, 순서만 다른 것은 같은 경우이다.

입력

첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) 다음 n개의 줄에는 각각의 동전의 가치가 주어진다. 동전의 가치는 100,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 경우의 수를 출력한다. 경우의 수는 231보다 작다.

코드

import sys
n,k = map(int,sys.stdin.readline().split())
d = [0]*(k+1)
coins = []
for i in range(n):
    coins.append(int(sys.stdin.readline()))
d[0] = 1
for i in coins:
    for j in range(i,k+1): #동전부터 순회
        if j-i >= 0:
            d[j] += d[j-i]
print(d[k])

풀이

d[i] 는 i원을 만들기 위한 경우의 수라고 생각하면 된다.

동전의 종류만큼 포문을 돌면서 d[j] += d[j-i] 를 해주면 된다.

728x90

문제

눈금의 간격이 1인 M×N(M,N≤100)크기의 모눈종이가 있다. 이 모눈종이 위에 눈금에 맞추어 K개의 직사각형을 그릴 때, 이들 K개의 직사각형의 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어진다.

예를 들어 M=5, N=7 인 모눈종이 위에 <그림 1>과 같이 직사각형 3개를 그렸다면, 그 나머지 영역은 <그림 2>와 같이 3개의 분리된 영역으로 나누어지게 된다.

<그림 2>와 같이 분리된 세 영역의 넓이는 각각 1, 7, 13이 된다.

M, N과 K 그리고 K개의 직사각형의 좌표가 주어질 때, K개의 직사각형 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어지는지, 그리고 분리된 각 영역의 넓이가 얼마인지를 구하여 이를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오른쪽 위 꼭짓점의 x, y좌표값이 빈칸을 사이에 두고 차례로 주어진다. 모눈종이의 왼쪽 아래 꼭짓점의 좌표는 (0,0)이고, 오른쪽 위 꼭짓점의 좌표는(N,M)이다. 입력되는 K개의 직사각형들이 모눈종이 전체를 채우는 경우는 없다.

출력

첫째 줄에 분리되어 나누어지는 영역의 개수를 출력한다. 둘째 줄에는 각 영역의 넓이를 오름차순으로 정렬하여 빈칸을 사이에 두고 출력한다.

코드

import sys
from collections import deque
m, n, k = map(int,sys.stdin.readline().split())
arr = [[0]*n for _ in range(m)]
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]

#직사각형 k개 1로 표시
for i in range(k):
    x1, y1, x2, y2 = map(int,sys.stdin.readline().split())
    for y in range(y1,y2):
        for x in range(x1,x2):
            arr[y][x] = 1
# print(arr)

#bfs
result = []

for i in range(m):
    for j in range(n):
        if arr[i][j] == 0: #갈 수 있는 길이면
            cnt = 1
            arr[i][j] = 1
            #bfs
            q = deque()
            q.append((i,j))
            while q:
                y,x = q.popleft()
                for c in range(4):
                    ny = y+ dy[c]
                    nx = x+ dx[c]
                    if 0<=ny<m and 0<=nx<n and arr[ny][nx] == 0:
                        cnt += 1
                        arr[ny][nx] = 1
                        q.append((ny,nx))
            result.append(cnt)
print(len(result))
result.sort()
for i in result:
    print(i,end=" ")

풀이

bfs로 풀이했다.

x,y가 y,x로 위치가 바뀌어서 계속 헷갈렸다.

728x90

문제

N×M크기의 배열로 표현되는 미로가 있다.

1 0 1 1 1 1
1 0 1 0 1 0
1 0 1 0 1 1
1 1 1 0 1 1

미로에서 1은 이동할 수 있는 칸을 나타내고, 0은 이동할 수 없는 칸을 나타낸다. 이러한 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오. 한 칸에서 다른 칸으로 이동할 때, 서로 인접한 칸으로만 이동할 수 있다.

위의 예에서는 15칸을 지나야 (N, M)의 위치로 이동할 수 있다. 칸을 셀 때에는 시작 위치와 도착 위치도 포함한다.

입력

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

출력

첫째 줄에 지나야 하는 최소의 칸 수를 출력한다. 항상 도착위치로 이동할 수 있는 경우만 입력으로 주어진다.

코드

import sys
from collections import deque
n, m = map(int,sys.stdin.readline().split())
arr = []
for i in range(n):
    arr.append(list(map(int,sys.stdin.readline().rstrip())))
#bfs
dx = [-1,0,1,0]
dy = [0,1,0,-1]
q = deque()
q.append((0,0))
while q:
    x,y = q.popleft()
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0<=nx<n and 0<=ny<m and arr[nx][ny] == 1:
            arr[nx][ny] = arr[x][y] + 1
            q.append((nx,ny))
print(arr[n-1][m-1])

풀이

bfs로 풀었다.

(0,0) 부터 이동해서 arr값이 1이면 이동하고 +1 해준다.

마지막 도착지점을 출력해주면 된다.

+ Recent posts