-
2229알고리즘/acmicpc 2016. 7. 24. 11:38
나이순으로 정렬이 이미 되었으니 해야 할 일은 여기서 연속된 배열을 어떻게 여러개로 나눠서 최대의 점수를 내는 조를 만드느냐이다.
(문제가 나이 정렬을 해주지 않고 냈으면 더 어려울 뻔 했는데 친절하게 나이 정렬을 해준 뒤에 문제를 풀라고 했다)
위 문제는 DP로 풀 수 있다. 먼저 다음과 같은 배열을 선언한다
dp[FROM][TO] : FROM학생부터 TO학생까지 조를 짤 때의 최대의 점수가 나오는 경우
목표는 FROM, TO까지 무조건 최대의 점수를 가지는 것이며 어떻게 분할 되는지는 상관하지 않는다
FROM에서 TO까지의 범위를 차근차근 늘려서 1번 학생부터 N번 학생가지 포함되는 경우까지 만들어준다.
#include<cstdio> #define MAXN 1000 #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define INF 10005 int dp[MAXN + 5][MAXN + 5]; int arr[MAXN + 5]; int main() { int N, i, j, len; int _min, _max; freopen("input.txt", "r", stdin); scanf("%d", &N); for (i = 0; i < N; i++) scanf("%d", &arr[i]); for (len = 0; len < N; len++) { for (i = 0; i + len < N; i++) { _min = INF, _max = 0; for (j = i; j <= i + len; j++) { _min = MIN(_min, arr[j]); _max = MAX(_max, arr[j]); dp[i][i + len] = MAX(dp[i][j] + dp[j + 1][i + len], dp[i][i+len]); } dp[i][i + len] = MAX(_max - _min, dp[i][i + len]); } } printf("%d\n", dp[0][N - 1]); return 0; }
하지만 위 방법은 O(N^3)이다. 2초 제한시간에 아슬아슬하게 통과했지만(772ms) 원칙상으로는 통과해선 안된다.다른 사람들의 코드를 봤는데 상위랭크는 대부분 O(N^2)로 풀었다.나와 푼 방식의 개념은 기본적으로 비슷하나 이분들은 FROM은 어차피 1이 될 것이기 때문에 이 경우를 무시하고 dp[TO]만 가지고 풀었다.새로운 dp[TO]를 만들기 위해 TO' < TO에서 dp[TO'] + (TO'+1 부터 TO 까지 조를 짤 경우)에 대한 최대값을 계속 업데이트 해줬다.내 방법보다 한 번 더 추상화해서 문제에 접근한 방식이다.정말 고수는 다르구나 하는 생각이 들었다.dp[1] = fabs(arr[1]-arr[0]); for(int i=2; i<n; i++) { maxnum=minnum=arr[i]; for(int j=i; j>0; j--) { maxnum = max(maxnum, arr[j]); minnum = min(minnum, arr[j]); dp[i] = max(dp[i], maxnum-minnum+dp[j-1]); } } printf("%d", dp[n-1]);