반응형

파이썬 / BOJ 백준 / 11054 가장 긴 바이토닉 부분 수열 - dp

 

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

 

11054번: 가장 긴 바이토닉 부분 수열

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

www.acmicpc.net

 

문제

수열 S가 어떤 수 Sk를 기준으로 S1 < S2 < ... Sk-1 < Sk > Sk+1 > ... SN-1 > SN을 만족한다면, 그 수열을 바이토닉 수열이라고 한다.
예를 들어, {10, 20, 30, 25, 20}{10, 20, 30, 40}, {50, 40, 25, 10} 바이토닉 수열이지만,  {1, 2, 3, 2, 1, 2, 3, 2, 1}{10, 20, 30, 40, 20, 30} 바이토닉 수열이 아니다.
수열 A가 주어졌을 때, 그 수열의 부분 수열 중 바이토닉 수열이면서 가장 긴 수열의 길이를 구하는 프로그램을 작성하시오.

 

풀이

1. dp로 풀 수 있는 문제입니다.

https://zidarn87.tistory.com/285 에 설명되어 있는 11053번 문제와 유사한 문제입니다.

2. 증가하는 수열을 위해 i = 0부터 bottom-up 식으로 현재 위치(i) 이전에 있는 원소(j)큰지 인하여, 크다면, 그 위치의 dp값에 1을 더해주면 됩니다.
3.
감소하는 수열을 위해 i = n-1 부터 top-down식으로 현재 위치(i)가 이전에 있는 원소(j)가 큰지를 확인하여, 크다면, 그 위치의 dp값에 1을 더해주면 됩니다.

4. 인덱스별 증가하는 수열 길이 + 감소하는 수열 길이의 합이 가장 큰 지점바이토닉 수열의 Sk 원소가 됩니다.

 

전체 코드

n = int(input())
arr = list(map(int, input().split()))
dpup   = [0 for i in range(n)]
dpdown = [0 for i in range(n)]
dpmix  = [0 for i in range(n)]

for i in range(n):
    for j in range(i):
        if arr[i] > arr[j] and dpup[i] < dpup[j]:
            dpup[i] = dpup[j]
    dpup[i] += 1
#print(dpup)

for i in range(n - 1, -1, -1):
    for j in range(n - 1, i, -1):
        if arr[i] > arr[j] and dpdown[i] < dpdown[j]:
            dpdown[i] = dpdown[j]
    dpdown[i] += 1
#print(dpdown)
for i in range(n):
    dpmix[i] = dpup[i] + dpdown[i] - 1
#print(dpmix)
print(max(dpmix))
반응형
반응형

파이썬 / BOJ 백준 / 11053 가장 긴 증가하는 부분 수열 - dp

 

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

 

문제

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

 

풀이

1. dp로 풀 수 있는 문제입니다.
2.
dp 리스트에 자신을 포함하여 만들 수 있는 부분 수열 크기저장합니다.

3. 현재 위치(i) 이전에 있는 원소(j)큰지 확인한다.

4. 크다면, 그 위치의 dp값에 1을 더해주면 됩니다.
(
, 현재 위치의 dp[i]dp[j]보다 작은 경우에만 적용합니다.)

5. 마지막에는 dp에 있는 값중 max를 출력하면 됩니다.

 

전체 코드

n = int(input())
a = list(map(int, input().split()))
dp = [0 for i in range(n)]
for i in range(n):
    for j in range(i):
        if a[i] > a[j] and dp[i] < dp[j]:
            dp[i] = dp[j]
    dp[i] += 1
    #print(dp)
print(max(dp))
반응형
반응형

파이썬 / BOJ 백준 / 2156 포도주 시식 - dp

 

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

 

2156번: 포도주 시식

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

www.acmicpc.net

문제

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


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


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


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

 

풀이

1. dp로 풀 수 있는 문제입니다.
2.
각 계단의 점수는 입력을 받아와 리스트 s에 넣습니다. (s[0]첫번째으로 생각합니다.)
1
차원 dp를 만들고, dp첫번째에는 s[0]을 넣습니다.
두번째 잔은 첫번째 잔을 마시고, 두번째 잔을 마시는 것이 최대이기 때문에 dp두번째에는 s[0] + s[1]을 넣어줍니다.

3.
dp[n]은 직전 잔을 마시는 경우와, 전전 잔을 마시는 경우가 있습니다. 두가지 경우의 최대값을 넣어줍니다. 그러면 dp에는 각 층까지의 최대값이 누적되어 들어가게 됩니다.

4.
직전 잔을 마시는 경우 (n-1)는 전전 (n-2) 마실 수 없으니, 전 잔(n-3)을 마실 수 있습니다. 식으로 만들면 dp[n-3] + s[i-1]로 표현할 수 있습니다.

5.
전전 잔을 마시는 경우는 dp[n-2]로 표현할 수 있습니다.

6.
이를 식으로 만들면 dp[i] = max(dp[i - 3] + s[i - 1] , dp[i - 2]) + s[i]로 표현할 수 있습니다.

 

전체 코드

n = int(input())
dp = [0] * 10002
s  = [0] * 10002

for i in range(1, n + 1):
    s[i] = int(input())

dp[1] = s[1]
dp[2] = s[1] + s[2]

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

 

반응형
반응형

파이썬 / BOJ 백준 / 10844번 쉬운 계단 수 - dp

 

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

 

10844번: 쉬운 계단 수

첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.

www.acmicpc.net

 

문제

45656이란 수를 보자.
이 수는 인접한 모든 자리수의 차이가 1이 난다. 이런 수를 계단 수라고 한다.
세준이는 수의 길이가 N인 계단 수가 몇 개 있는지 궁금해졌다.
N
이 주어질 때, 길이가 N인 계단 수가 총 몇 개 있는지 구하는 프로그램을 작성하시오. (0으로 시작하는 수는 없다.)

 

풀이

wjs

1. DP(동적계획법)을 이용해 풀 수 있는 문제입니다. DP테이블은 이차원 리스트이며 DP[자리 수][앞에 오는 숫자]=경우의 로 표현합니다.

 

2. 앞에 오는 숫자 = 0이면 아래와 같은 식으로 표현합니다. 0 다음에는 1밖에 올 수 없습니다. 

DP[자리 수][0] = DP[자리 수 - 1][1]

맨앞에는 0올수 없고, 그 아래 자리수부터는 0이 올 수 있으니, 맞교환하는 식으로 하여, 간단하게 식을 만듭니다.

 

 3. 앞에 오는 숫자 = 1~8 이면 아래와 같은 식으로 표현합니다. 1 ~ 8은 각각 2개씩 올 수 있습니다. 

DP[자리 수][앞에 오는 숫자] = DP[자리 수 - 1][앞에 오는 숫자 -1] + DP[자리 수 - 1][앞에 오는 숫자 + 1]

 

 4. 앞에 오는 숫자 = 9이면 아래와 같은 식으로 표현합니다.

DP[자리 수][9] = DP[자리 수 - 1][8]

 

5. 마지막에 DP[자리수]에 있는 값을 모두 더하고, 1000000000의 나머지를 구해줍니다.

 

전체 코드

n = int(input())
dp = [[0 for i in range(10)] for j in range(101)]
for i in range(1, 10):
    dp[1][i] = 1
for i in range(2, n + 1):
    for j in range(10):
        if j == 0:
            dp[i][j] = dp[i - 1][1]
        elif j == 9:
            dp[i][j] = dp[i - 1][8]
        else:
            dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1]
    #print(dp[i])
print(sum(dp[n]) % 1000000000)
반응형

+ Recent posts