PS

BOJ 2228 - 구간 나누기

728x90

www.acmicpc.net/problem/2228

 

2228번: 구간 나누기

N(1≤N≤100)개의 수로 이루어진 1차원 배열이 있다. 이 배열에서 M(1≤M≤⌈(N/2)⌉)개의 구간을 선택해서, 구간에 속한 수들의 총 합이 최대가 되도록 하려 한다. 단, 다음의 조건들이 만족되어야

www.acmicpc.net

 

이 문제는 DP 로 풀어야하는 문제다

 

규칙을 찾는게 꽤나 어려워서, 시간이 너무 오래걸렸다 그래서 결국 다른 블로그들의 글을 참조했다.

DP 배열을 다음과 같이 잡는다

 

int dp[n][m] : "1 ~ n 번째 인덱스까지의 1차원 배열에서 m 개의 구간을 선택했을때 구간합의 최대값"

 

이렇게 DP 배열을 잡아주고, -1로 초기화 한뒤,

DP 배열을 채우기 위한 재귀함수를 만들어준다

 

재귀함수의 내부 로직은 n 번째 인덱스를 제외한 이전 인덱스까지의 경우의 수를 재귀함수로 계산한 뒤에

i ~ n 구간까지의 누적합을 구하고 인접하지 않는 구간 범위에서 m - 1 개의 구간합을 구하는 식으로 진행한다.

 

 

 

- c++

#include <bits/stdc++.h>
 
#define MAX_N 101
#define MAX_M 51
#define MIN -3276800
 
using namespace std;
 
int N, M;
int arr[MAX_N];
int dp[MAX_N][MAX_M]; // dp[n][m] : 1 ~ n 인덱스까지 1차원 배열에서 m 개의 구간 선택시 합의 최대 
 
int solve(int n, int m) {
    // base case
    if (m == 0return 0// 구간을 하나도 선택하지 않을때 
    if (n <= 0return MIN; // 에러처리 
    if (dp[n][m] != -1return dp[n][m];
    
    int sum = 0;
    dp[n][m] = solve(n - 1, m); // n 번째를 제외한 이전 구간들의 경우의 수 계산 (재귀함수) 
    for (int i = n; i > 0--i) {
        sum += arr[i]; // i ~ n 의 구간합
        int temp = solve(i - 2, m - 1+ sum; // 인접하지 않는 범위에서, m - 1 개의 구간합의 최댓값 구함
        dp[n][m] = max(dp[n][m], temp);
    } 
    
    return dp[n][m];
}
 
int main() {
    cin.tie(0); ios_base::sync_with_stdio(0);
    
    cin >> N >> M;
    for (int i = 1; i <= N; ++i) cin >> arr[i];
    
    memset(dp, -1sizeof(dp));
    
    cout << solve(N, M);
    
    return 0;
}
cs

 

 

 

 

728x90

'PS' 카테고리의 다른 글

BOJ 1202 - 보석 도둑  (0) 2021.02.20
BOJ 5557 - 1학년  (0) 2021.02.14
BOJ 2212 - 센서  (0) 2021.02.14
BOJ 8980 - 택배  (0) 2021.02.13
BOJ 1781 - 컵라면  (0) 2021.02.12