알고리즘/acmicpc
2229
kwony
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]);