728x90

문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

코드

#11053
import sys
n = int(sys.stdin.readline())
a = list(map(int,sys.stdin.readline().split()))
d = [0]*n

for i in range(n):
    for j in range(i):
        if a[j] < a[i] and d[j] > d[i]:
            d[i] = d[j]
    d[i] += 1
print(max(d))

풀이

A = {10, 20, 10, 30, 20, 50} 로 경우의 수를 나눠서 구해보면 된다.

반복문을 돌면서, 자기 자신보다 작은 수열 중 가장 길이가 긴 수열의 크기 +1

 

 if a[i]>a[j]  -> 자기 자신보다 작은 수열

and d[j] > d[i] -> 가장 길이가 긴 수열의 크기

 

728x90

문제

효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규칙이 있다.

  1. 포도주 잔을 선택하면 그 잔에 들어있는 포도주는 모두 마셔야 하고, 마신 후에는 원래 위치에 다시 놓아야 한다.
  2. 연속으로 놓여 있는 3잔을 모두 마실 수는 없다.

효주는 될 수 있는 대로 많은 양의 포도주를 맛보기 위해서 어떤 포도주 잔을 선택해야 할지 고민하고 있다. 1부터 n까지의 번호가 붙어 있는 n개의 포도주 잔이 순서대로 테이블 위에 놓여 있고, 각 포도주 잔에 들어있는 포도주의 양이 주어졌을 때, 효주를 도와 가장 많은 양의 포도주를 마실 수 있도록 하는 프로그램을 작성하시오. 

예를 들어 6개의 포도주 잔이 있고, 각각의 잔에 순서대로 6, 10, 13, 9, 8, 1 만큼의 포도주가 들어 있을 때, 첫 번째, 두 번째, 네 번째, 다섯 번째 포도주 잔을 선택하면 총 포도주 양이 33으로 최대로 마실 수 있다.

입력

첫째 줄에 포도주 잔의 개수 n이 주어진다. (1 ≤ n ≤ 10,000) 둘째 줄부터 n+1번째 줄까지 포도주 잔에 들어있는 포도주의 양이 순서대로 주어진다. 포도주의 양은 1,000 이하의 음이 아닌 정수이다.

출력

첫째 줄에 최대로 마실 수 있는 포도주의 양을 출력한다.

코드

#2156
import sys
n = int(sys.stdin.readline())
arr = [0]*10000 #포도주
for i in range(n):
    arr[i] = int(sys.stdin.readline())

#dp테이블
#dp[i] = 0부터 i번째 포도주까지 최대로 마신 양
dp = [0] * 10000
dp[0] = arr[0]
dp[1] = arr[0] + arr[1]
dp[2] = max(arr[0]+arr[2], arr[1]+arr[2], dp[1])

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

풀이

다이나믹 프로그래밍이다.

dp[i] 는 처음부터 i번째까지 최대한 마신 포도주의 양이다.

dp[0] 부터 계산하면 점화식이 나오고 계산한다.

그 중 가장 큰 값을 출력하면 된다.

 

출처 : 백준

728x90

문제

백준이는 동생에게 "가운데를 말해요" 게임을 가르쳐주고 있다. 백준이가 정수를 하나씩 외칠때마다 동생은 지금까지 백준이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 백준이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.

예를 들어 백준이가 동생에게 1, 5, 2, 10, -99, 7, 5를 순서대로 외쳤다고 하면, 동생은 1, 1, 2, 2, 2, 2, 5를 차례대로 말해야 한다. 백준이가 외치는 수가 주어졌을 때, 동생이 말해야 하는 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 백준이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 백준이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.

출력

한 줄에 하나씩 N줄에 걸쳐 백준이의 동생이 말해야 하는 수를 순서대로 출력한다.

코드

import sys
import heapq
n = int(sys.stdin.readline())
left_heap = [] #최대힙
right_heap = [] #최소힙
for _ in range(n):
    num = int(sys.stdin.readline())
    if len(left_heap) == len(right_heap):
        heapq.heappush(left_heap,-num)
    else:
        heapq.heappush(right_heap,num)

    if len(left_heap)>=1 and len(right_heap)>=1 and -left_heap[0] > right_heap[0]:
        #중간값이 중간값이 아니면
        l_value = -heapq.heappop(left_heap)
        r_value = heapq.heappop(right_heap)

        heapq.heappush(left_heap,-r_value)
        heapq.heappush(right_heap,l_value)
    print(-left_heap[0])

풀이

우선순위 큐를 사용해서 풀어야겠다는 생각까지는 했지만 시간초과가 났다.

다른 사람의 풀이들을 찾아보고 공부했다.

 

최대힙, 최소힙 모두 사용해야한다.

최대힙 : 중간 값 보다 작은 값들을 삽입한다. (내림차순 정렬)

최소힙 : 중간값보다 큰 값들을 삽입한다. (오름차순 정렬)

이 두가지만 생각하고 풀면 최대힙의 첫번째 원소값이 결국 배열의 중간값이 된다.

 

최대힙을 left_heap

최소힙을 right_heap으로 뒀다.

 

1) left_heap에 먼저 삽입

2) 다음, right_heap에 삽입 

3) 둘 다 원소가 있고  중간 값보다 더 큰 값이 left_heap[0]에 있을때.... 

len(left_heap) >=1 and len(right_heap)>=1 and -left_heap[0] > right_heap[0]: 

-left_heap[0] , right_heap[0] 이 값을 서로 부호와 원소를 바꿔준다.

 

right_heap에 있는 모든 수는 left_heap에 있는 수보다는 커야한다. (중간값이 left_heap[0]에 있으니까!!!! )

4) 중간값 출력 left_heap[0]

 

 

728x90

문제

도현이의 집 N개가 수직선 위에 있다. 각각의 집의 좌표는 x1, ..., xN이고, 집 여러개가 같은 좌표를 가지는 일은 없다.

도현이는 언제 어디서나 와이파이를 즐기기 위해서 집에 공유기 C개를 설치하려고 한다. 최대한 많은 곳에서 와이파이를 사용하려고 하기 때문에, 한 집에는 공유기를 하나만 설치할 수 있고, 가장 인접한 두 공유기 사이의 거리를 가능한 크게 하여 설치하려고 한다.

C개의 공유기를 N개의 집에 적당히 설치해서, 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오.

입력

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

출력

첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.

코드

import sys
n,c = map(int,sys.stdin.readline().split())
house = []
for _ in range(n):
    house.append(int(sys.stdin.readline()))
#집 오름차순 정렬
house.sort()
start = 1
end = house[-1]-house[0] #집 좌표 차이 최댓값
result = 0
while start<=end:
    mid = (start+end) // 2
    #처음 집부터 공유기 설치
    now = house[0]
    cnt = 1

    for i in range(1,len(house)):
        if house[i] >= now + mid:
            #공유기 설치
            cnt+=1
            now = house[i]
    #공유기 개수가 c가 되어야 한다.
    if cnt >= c:
        start = mid + 1
        result = mid
    else:
        end = mid - 1
print(result)

풀이

집 좌표가 10억이 넘어서 이분탐색으로 풀이해야 시간 초과가 나지 않는다.

집 좌표 차이가 중요하므로 오름차순으로 정렬하고 탐색을 시작한다.

start = 1 , end = 마지막 원소 - 첫번째 원소  ( 하면 가장 큰 차이의 좌표 차가 나온다.)

 

이분 탐색을 진행한다.

  1. 설치된 공유기 수가 c보다 작으면  - 공유기를 더 설치해야 한다. end = mid-1
  2. 설치된 공유기 수가 c보다 크거나 같다면 - 공유기를 덜 설치해야한다. start = mid+1

 

출처 : 백준

728x90

문제

절댓값 힙은 다음과 같은 연산을 지원하는 자료구조이다.

  1. 배열에 정수 x (x ≠ 0)를 넣는다.
  2. 배열에서 절댓값이 가장 작은 값을 출력하고, 그 값을 배열에서 제거한다. 절댓값이 가장 작은 값이 여러개일 때는, 가장 작은 수를 출력하고, 그 값을 배열에서 제거한다.

프로그램은 처음에 비어있는 배열에서 시작하게 된다.

입력

첫째 줄에 연산의 개수 N(1≤N≤100,000)이 주어진다. 다음 N개의 줄에는 연산에 대한 정보를 나타내는 정수 x가 주어진다. 만약 x가 0이 아니라면 배열에 x라는 값을 넣는(추가하는) 연산이고, x가 0이라면 배열에서 절댓값이 가장 작은 값을 출력하고 그 값을 배열에서 제거하는 경우이다. 입력되는 정수는 -231보다 크고, 231보다 작다.

출력

입력에서 0이 주어진 회수만큼 답을 출력한다. 만약 배열이 비어 있는 경우인데 절댓값이 가장 작은 값을 출력하라고 한 경우에는 0을 출력하면 된다.

코드

import sys
import heapq
n = int(sys.stdin.readline())
q = []
for i in range(n):
    x = int(sys.stdin.readline())
    if x == 0:
        #배열에서 가장 작은 값 출력 없으면 0
        if len(q)==0:
            print(0)
        else:
            print(heapq.heappop(q)[1])
    else:
        #배열에 x값 넣기
        heapq.heappush(q,(abs(x),x))

풀이

우선순위 큐를 사용한다.

절댓값이 작은 수 먼저 출력, 절댓값이 같은 수가 여러 개면 값이 작은 수 출력. 

이를 봐서 (abs(x),x) 튜플 형태로 절댓값과 수를 함께 우선순위 큐에 삽입한다.

우선순위 큐는 디폴트로 튜플의 첫 번째 값인 절댓값 기준으로 정렬된다.

728x90

문제

국가의 역할 중 하나는 여러 지방의 예산요청을 심사하여 국가의 예산을 분배하는 것이다. 국가예산의 총액은 미리 정해져 있어서 모든 예산요청을 배정해 주기는 어려울 수도 있다. 그래서 정해진 총액 이하에서 가능한 한 최대의 총 예산을 다음과 같은 방법으로 배정한다.

  1. 모든 요청이 배정될 수 있는 경우에는 요청한 금액을 그대로 배정한다.
  2. 모든 요청이 배정될 수 없는 경우에는 특정한 정수 상한액을 계산하여 그 이상인 예산요청에는 모두 상한액을 배정한다. 상한액 이하의 예산요청에 대해서는 요청한 금액을 그대로 배정한다. 

예를 들어, 전체 국가예산이 485이고 4개 지방의 예산요청이 각각 120, 110, 140, 150이라고 하자. 이 경우, 상한액을 127로 잡으면, 위의 요청들에 대해서 각각 120, 110, 127, 127을 배정하고 그 합이 484로 가능한 최대가 된다. 

여러 지방의 예산요청과 국가예산의 총액이 주어졌을 때, 위의 조건을 모두 만족하도록 예산을 배정하는 프로그램을 작성하시오.

입력

첫째 줄에는 지방의 수를 의미하는 정수 N이 주어진다. N은 3 이상 10,000 이하이다. 다음 줄에는 각 지방의 예산요청을 표현하는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 값들은 모두 1 이상 100,000 이하이다. 그 다음 줄에는 총 예산을 나타내는 정수 M이 주어진다. M은 N 이상 1,000,000,000 이하이다. 

출력

첫째 줄에는 배정된 예산들 중 최댓값인 정수를 출력한다. 

코드

import sys
input = sys.stdin.readline
n = int(input())
money = list(map(int,input().split()))
m = int(input())

start,end = 0,max(money)

while start<=end:
    mid = (start+end)//2 #상한액
    num = 0
    for i in money:
        # 상한액보다 요청 금액이 크면 상한액 배정
        if i >= mid:
            num += mid
        else: #아니면 요청 금액 배정
            num += i
    # 배정금액이 총 예산보다 작으면
    if num <= m:
        start = mid + 1
    else:
        end = mid -1
print(end)

풀이

특정 정수 상한액을 정하고 계산해야한다는 부분에서 이분 탐색을 해야 한다고 결론지었다.

start = 0, end = max(요청 금액)

mid = (start+end)//2

start<=end 가 될 때까지 이분 탐색을 반복하자.

 

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는 최소힙이 디폴트다.

+ Recent posts