[C++] 백준(BOJ) - 1912 : 연속합
인프런에 있는 큰돌님의 강의 10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트를 듣고 정리한 필기입니다.
문제
n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.
예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.
입력
첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.
출력
첫째 줄에 답을 출력한다.
알고리즘
- 그리디
- DP
풀이
- 브루트포스
- 10만 * 10만 => 시간복잡도 초과
- 그리디
- 구간 진행을 쭉해보고 진행한 구간까지 누적합이 음수가 되기 전까지는 일단 더하며 최대 값을 갱신해 나간다
- 구간 누적합이 음수가 되는 경우 임시 누적합 sum을 초기화
- 구간 진행을 쭉해보고 진행한 구간까지 누적합이 음수가 되기 전까지는 일단 더하며 최대 값을 갱신해 나간다
- DP
- 점화식
dp[i] = dp[i-1] + a[i]을 기반으로 res 값을 최대값으로 갱신해 나가기- 더할 누적값이 큰지 아닌지를 판단하여 dp[i] 값을 어떻게 할지 결정해 나가기
- 점화식
코드 1 : 그리디
// BOJ-1912 : 연속합
#include <bits/stdc++.h>
using namespace std;
const int INF = 2147000000;
int n, a, sum = 0, res = -INF;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a;
sum += a;
res = max(res, sum);
if (sum < 0)
{
sum = 0;
}
}
cout << res << '\n';
return 0;
}
코드 2 : DP
// BOJ-1912 : 연속합
#include <bits/stdc++.h>
using namespace std;
const int INF = 2147000000;
int n, a, sum = 0, res = -INF;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> n;
vector<int> v;
vector<int> dp(n);
for (int i = 0; i < n; i++)
{
cin >> a;
v.push_back(a);
}
res = v[0];
for (int i = 0; i < n; i++)
{
dp[i] = v[i];
if (i == 0) continue;
if (dp[i] < dp[i - 1] + v[i]) dp[i] = dp[i - 1] + v[i];
res = max(res, dp[i]);
}
cout << res << '\n';
return 0;
}
평가
- 단순한 구현 문제로 풀 수 있지만 DP 강의를 듣고 다시 와서 점화식 만드는 연습 다시 해보기