티스토리 뷰

알고리즘 문제풀이

BOJ 30960 조별 과제

금복이 2024. 1. 31. 20:39

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

 

30960번: 조별 과제

학번이 $3, 1$인 사람을 한 조로 묶고, $4, 5, 9$인 사람을 한 조로 묶으면 각 조의 어색함은 $(3-1) = 2$와 $(9-4) = 5$이고, 합은 $7$이다. 이 방법이 각 조의 어색함의 합을 최소로 하는 방법이다.

www.acmicpc.net

 

 

정해는 정렬+누적합이지만, 아이디어가 떠오르지 않아 DP로 해결했습니다.

본 글에선 두 가지 방법 모두 소개합니다.

 

 

 

1. 정렬+누적합

 

 

 

일단 입력받은 배열을 정렬한 상태라고 합시다. 앞에서부터 3명씩 묶을 사람을 정합니다. 맨 처음 3명을 묶을 경우 어색함의 총합은  $(a_{2}-a_{0}) + (a_{4}-a_{3}) + (a_{6}-a_{5})$입니다. 이 값을 $sum$이라고 합시다. 여기서 그 다음 세 명을 묶었을 때의 어색함의 총합을 구하려면 $sum - (a_{2}-a_{0}) - (a_{4}-a_{3}) + (a_{1}-a_{0}) + (a_{4}-a_{2})$를 계산하면 됩니다. 즉, 부분 부분을 빼고 더해주면 됩니다. 이러한 관계를 일반화하여 모든 경우의 수를 살펴보는 방법이 첫 번째 풀이입니다.

 

 

#include <bits/stdc++.h>
#define sz(x) (int)x.size()
using namespace std;
typedef long long ll;
int N, arr[500001];

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

    for(int i=0; i<N; i++){
        cin >> arr[i];
    }

    sort(arr, arr+N);

    int sum = arr[2] - arr[0];
    for(int i=4; i<N; i+=2){
        sum += (arr[i] - arr[i-1]);
    }

    int ans = sum;
    for(int i=2; i<N-1; i+=2){
        sum -= (arr[i] - arr[i-2]);
        sum -= (arr[i+2] - arr[i+1]);
        sum += (arr[i-1] - arr[i-2]);
        sum += (arr[i+2] - arr[i]);

        ans = min(ans, sum);
    }

    cout << ans;
}

 

 

 

 

 

 

2. DP

dp[i][0] : 사람 수가 $i$명이고, 아직 3명을 한 팀으로 묶지 않은 경우 어색함 총합의 최솟값

dp[i][1] : 사람 수가 $i$명이고, 3명을 한 팀으로 묶은 적이 있는 경우 어색함 총합의 최솟값

 

이라고 정의합시다.

 

그러면 i가 짝수일 때는 dp[i][1]은 정의되지 않습니다. i가 짝수이면 3명을 한 팀으로 묶은 적이 있다면 한 명이 남아버리기 때문입니다.

 

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, arr[500001], dp[500001][2];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    cin >> n;

    for(int i=1; i<=n; i++){
        cin >> arr[i];
    }
    
    sort(arr+1, arr+1+n);

    dp[1][1] = 1e9+8;
    dp[1][0] = 1e9+8;

    for(int i=2; i<=n; i++){
        if(i%2==0){
            dp[i][0] = dp[i-2][0] + arr[i] - arr[i-1];
            dp[i][1] = 1e9+8;
        }else{
            dp[i][0] = dp[i-2][0] + arr[i] - arr[i-1];
            dp[i][1] = min(dp[i-2][1] + arr[i] - arr[i-1], dp[i-3][0] + arr[i] - arr[i-2]);
        }
    }

    cout << dp[n][1];

}

 

'알고리즘 문제풀이' 카테고리의 다른 글

BOJ 2015 수들의 합 4  (1) 2024.01.31
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31