전공/알고리즘

백준 16494 가장 큰 값

xkdlaldfjtnl 2022. 3. 15. 01:25

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

 

16494번: 가장 큰 값

첫째 줄에 N과 M(1 ≤ M ≤ N ≤ 20)이 주어진다. 둘째 줄에는 수열에 속한 수가 주어진다. 수는 공백으로 구분되어져 있고, 절댓값이 100보다 작거나 같은 정수이다.

www.acmicpc.net

이전에 생각 안 난 문제를 적어두었는데 사람들이 유입되길래 풀어봄 

 

 문제 조건에서 빠진 부분이 있는데 중복된 index를 뽑을 수는 없다. 

 

문제는 M개의 그룹을 뽑을 때 그 그룹 합의 최대를 구하는 문제이다. 

모든 i,j 쌍에 대해서 누적합을 구한 뒤, dp식을 세운다.

 

dp[i][j] := [i, j]에서의 연속된 수열의 최대 합 

따라서 N^4으로 dp테이블을 만들 수 있다. 

 

그 다음에 1~N까지 중 M개의 그룹을 뽑는 모든 경우에 대해서 계산하면 된다.

이번에 이 문제를 풀면서 Next Permutation 함수를 처음으로 구글링해서 써보았는데 아주 편하다. 

 

--------------------------------------------------------------------------------------------------------------

1~N개의 그룹으로 이루어진 것 모든 경우에 대해서 브루트포스 계산도 가능하다. 
시간복잡도 O(2^N)

N = 20이므로 가능 

#include <bits/stdc++.h>
using namespace std;
#define TEST int tt; cin >> tt; while (tt--)
#define all(v) (v).begin(), (v).end()
#define pii pair<int, int>
#define pll pair<ll, ll>
#define tii tuple<int, int, int>
#define ll long long
#define FASTIO ios_base::sync_with_stdio(false); cin.tie(0);
const int MAX = 200'005;
const int INF = 1e9 + 1;
const ll MOD = 1'000'003;

int num[50];
int sum[50][50];
int dp[40][40];


int main() {
    FASTIO
    int N, M;
    cin >> N >> M;
    for(int i=1; i<=N; i++){
        cin >> num[i];
    }
    for(int i=1; i<=N; i++){
        for(int j=i; j<=N; j++)dp[i][j] = -INF;
    }
    vector<int> v;
    for(int i=0; i<N; i++){
        for(int j=1; j<=N; j++){
            if(j+i>N)break;
            sum[j][j+i] = sum[j][j+i-1] + num[j+i];
        }
    }
    for(int i=1; i<=N; i++){
        for(int j=i; j<=N; j++){
            for(int a=i; a<=j; a++){
                for(int b=a; b<=j; b++){
                    dp[i][j] = max(dp[i][j], sum[a][b]);
                }
            }
        }
    }
    vector<int> a;
    vector<int> b;
    int cnt = 0;
    for(int i=1; i<=N; i++){
        a.emplace_back(i);
        if(cnt<M-1){
            b.emplace_back(1);
            cnt++;
        }
        else b.emplace_back(0);
    }
    int before;
    int ans = -INF;
    do {
        int sum =0;
        before = 1;
        for (int i = 0; i < a.size(); ++i) {
            if (b[i] == 1){
                sum += dp[before][a[i]];
                before = a[i]+1;
            }
        }
        if(before<=N){
            sum+=dp[before][N];
            ans = max(ans, sum);
        }
    } while (prev_permutation(b.begin(), b.end()));
    cout << ans;
}