본문 바로가기

백준/골드

[백준 2228번} 구간 나누기 (C++)

문제링크 : https://www.acmicpc.net/problem/2228

 

2228번: 구간 나누기

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

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 987654321;

int N, M;
int arr[101], dp[101][51];

int func(int n, int m)
{
    if(m==M) return 0; //구간 선택 종료 
    if(n<=0) return -MAX; //에러 (범위 밖)
    if(dp[n][m]) return dp[n][m]; //값이 있으면 바로 반환

    int sum = 0;   
    dp[n][m] = func(n-1, m); //(~n-1 + n+1~) (현재 n이 구간에 포함되지 않는 경우)
    for(int i=n; i>0; i--)
    {
        sum += arr[i]; //누적합
        dp[n][m] = max(dp[n][m], func(i-2, m+1) + sum); //(~n-2 + n~) (현재 n이 구간에 포함되는 경우)와 위에서 구한 구간과 비교
    }
    return dp[n][m];
}

int main()
{
    ios_base::sync_with_stdio(0); 
	cin.tie(0);
    
    cin >> N >> M;

    for(int i=1; i<=N; i++) cin >> arr[i];

    cout << func(N, 0);
    return 0;
}

 

먼저 dp[N][M]은 N이 현재 위치이고, M은 현재 구간이다

그리고 갱신할 케이스가 아래와 같이 2가지가 존재한다.

현재 N이 구간에 포함된 경우
(?~N-2 + N~?)

현재 N이 구간에 포함되지 않은 경우
(?~N-1 + N+1~?)

 

 

재귀를 통해서 위 케이스 2가지를 통해 dp를 갱신하게 된다.

해당 재귀에서 N이 감소하는 방식으로 값 탐색이 이루어지기 때문에 N이 범위 밖으로 나가면 예외처리를 해준다.

그리고 구간에 대해 시작은 0으로 1개씩 추가해나가며 주어진 M개에 도달하면 종료한다.

 

현재 N이 구간에 포함되지 않은 경우는 말 그대로 구간에 포함되지 않았기 때문에 재귀로 값을 넘길 때 m은 그대로이다.

현재 N이 구간에 포함되는 경우는 구간이 하나 감소했으므로 m을 1 증가시켜서 넘겨준다.

해당 문제에서 인접하지 않은 구간을 체크해야 하므로 현재 누적합을 더한 이후 나머지 구간은 N-2를 하여 현재 위치 기준 전전값의 위치를 넘기게 된다.

 

 

'백준 > 골드' 카테고리의 다른 글

[백준 14852번] 타일 채우기 3 (C++)  (0) 2024.01.15
[백준 17845번] 수강 과목 (C++)  (0) 2024.01.13
[백준 1766] 문제집 (C++)  (0) 2024.01.07
[백준 18513번] 샘터 (C++)  (0) 2024.01.04
[백준 16509번] 장군 (C++)  (0) 2024.01.02