[C++] 백준(BOJ) - 1912 : 연속합

인프런에 있는 큰돌님의 강의 10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트를 듣고 정리한 필기입니다.

문제

BOJ - 1912 : 연속합(링크)

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.

입력

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

출력

첫째 줄에 답을 출력한다.

알고리즘

  1. 그리디
  2. 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 강의를 듣고 다시 와서 점화식 만드는 연습 다시 해보기

© 2023 Jinsoo Lee. All rights reserved.

Powered by Hydejack v9.1.6