주식 투자는 미래의 이익을 기대하며 자본을 투입하는 행위이다. 하지만 매일매일의 시장 상황을 정확하게 예측하는 것은 어려운 일이다. 이번에 다룰 백준 13416번 문제는 주어진 주식 데이터에서 최대의 이익을 낼 수 있는 방법을 찾아내는 문제이다. 이 글에서는 문제의 상세한 설명과 함께 효율적인 알고리즘을 통해 문제를 해결해보도록 하겠다.
문제 : https://www.acmicpc.net/problem/13416
문제 설명
환규는 오늘부터 주식 투자를 하려고 한다. 그는 정보를 수집한 결과 A사, B사, C사 세 개의 회사에 투자하기로 결정했다. 그러나 그는 어떤 주식이 오를지, 떨어질지 예측하는 것이 아직은 힘들었다. 그래서 다음과 같은 투자 전략을 세웠다.
- 하루에는 최대 한 개의 회사 주식만 살 수 있다.
- 서로 다른 날에는 서로 다른 회사의 주식을 살 수 있지만, 하루에는 최대 한 개의 회사 주식만 구매한다.
- 매일 장이 열리기 전에 그날 주식을 살 회사를 정하고, 장이 열릴 때 해당 회사의 주식을 산다.
- 장이 닫힐 때 그날 산 주식을 모두 판다.
- 만약 세 회사 중 어느 곳도 수익이 날 것 같지 않으면 주식을 구매하지 않아도 된다.
환규는 주식을 처음 해보기 때문에 이 전략으로 주식 투자를 했을 때 얼마나 이익을 낼 수 있는지 궁금해졌다. 그래서 투자하려는 회사들의 지난 N일 동안의 주식 데이터를 이용해 N일 동안 위의 규칙을 지키며 주식 투자를 했을 때 과연 얼마를 벌 수 있는지 계산해 보기로 했다.
환규는 각 회사별로 장이 열릴 때 주식을 사고, 장이 닫힐 때 모두 팔았을 경우 매일 얼마를 벌 수 있었는지 정리했다. 다음은 N = 4일 때 환규가 정리한 데이터를 나타내는 표이다.
| 날짜 | A사 | B사 | C사 |
|---|---|---|---|
| 1일 | 500 | 800 | 200 |
| 2일 | 300 | 0 | 300 |
| 3일 | -100 | -200 | -400 |
| 4일 | 600 | 200 | 300 |
- 양수는 이익을, 음수는 손해를 나타내며, 0은 이익도 손해도 없음을 의미한다.
- 예를 들어, 1일째에 A사의 주식을 장이 열릴 때 사고, 장이 닫힐 때 팔면 500의 이익을 얻을 수 있었다.
- 3일째에 C사의 주식을 장이 열릴 때 사고, 장이 닫힐 때 판다면 400의 손해가 발생한다.
데이터를 분석하던 환규는 자신이 정리한 데이터를 이용해서 N일 동안 규칙을 지키면서 매일 최적의 투자를 할 경우 최대 얼마를 벌 수 있었는지 궁금해졌다.
- 예를 들어 위 표에서:
- 1일째에는 B사의 주식을 사면 가장 많은 이익을 남길 수 있다 (800).
- 2일째에는 A사 또는 C사의 주식을 사면 가장 많은 이익을 남길 수 있다 (300).
- 3일째에는 어떤 주식을 사도 손해가 나므로 주식을 사지 않는다.
- 4일째에는 A사의 주식을 사면 된다 (600).
- 이렇게 주식 투자를 할 경우 환규는 800 + 300 + 0 + 600 = 1700으로, 최대 1700의 이익을 남길 수 있다.
문제: 환규가 N일 동안 위의 규칙을 지키며 최적의 투자를 했을 때 얻을 수 있는 최대 이익을 계산하는 프로그램을 작성하시오.
접근 방식
이 문제는 각 날마다 선택할 수 있는 가장 큰 이익을 선택하는 그리디(Greedy) 알고리즘으로 해결할 수 있다. 매일 세 회사의 손익 중에서 양수인 값 중 최대값을 선택하고, 음수이거나 0이면 그날은 투자를 하지 않는다.
알고리즘 단계
- 입력 처리:
- 테스트 케이스 수 T를 입력받는다.
- 각 테스트 케이스마다 주식 데이터의 일수 N을 입력받는다.
- 매일의 최대 이익 계산:
- 각 날마다 A사, B사, C사의 손익을 입력받는다.
- 세 회사의 손익 중에서 최대값을 찾는다.
- 최대값이 양수이면 총 이익에 더하고, 그렇지 않으면 아무 것도 하지 않는다.
- 결과 출력:
- 총 이익을 출력한다.
이 알고리즘은 매일 최적의 선택을 하므로 전체 기간 동안의 최대 이익을 구할 수 있다. 시간 복잡도는 **O(N)**으로, N은 주식 데이터의 일수이다.
C++ 코드와 설명
코드
| |
코드 설명
- 헤더 파일 포함
#include <iostream>: 표준 입출력을 사용하기 위해 포함한다.#include <algorithm>:max함수를 사용하기 위해 포함한다.
using namespace std;- 표준 네임스페이스를 사용하여 코드의 가독성을 높인다.
- 메인 함수 정의
int main() { ... }: 프로그램의 시작점이다.
- 테스트 케이스 처리
int T; cin >> T;: 테스트 케이스 수를 입력받는다.while (T--) { ... }: 테스트 케이스 수만큼 반복한다.
- 주식 데이터 처리
int N; cin >> N;: 주식 데이터의 일수를 입력받는다.long long totalProfit = 0;: 총 이익을 저장할 변수를 초기화한다.for (int i = 0; i < N; ++i) { ... }: 각 날에 대해 반복한다.int A, B, C; cin >> A >> B >> C;: 각 회사의 손익을 입력받는다.int maxProfit = max({A, B, C});: 세 회사의 손익 중 최대값을 찾는다.if (maxProfit > 0) { totalProfit += maxProfit; }: 최대값이 양수이면 총 이익에 더한다.
- 결과 출력
cout << totalProfit << endl;: 총 이익을 출력한다.
- 프로그램 종료
return 0;: 프로그램을 정상적으로 종료한다.
코드 동작 단계별 설명
- 입력 받기
- 프로그램은 먼저 테스트 케이스 수 T를 입력받는다.
- 테스트 케이스 반복
- 각 테스트 케이스마다 다음을 수행한다.
- 주식 데이터의 일수 N을 입력받는다.
- 총 이익을 저장할 변수 totalProfit을 0으로 초기화한다.
- 각 테스트 케이스마다 다음을 수행한다.
- 일별 데이터 처리
- N일 동안 다음을 반복한다.
- A사, B사, C사의 손익 A, B, C를 입력받는다.
max({A, B, C})를 사용하여 세 값 중 최대값 maxProfit을 찾는다.- maxProfit이 양수이면 totalProfit에 더한다.
- N일 동안 다음을 반복한다.
- 결과 출력
- 각 테스트 케이스마다 계산된 totalProfit을 출력한다.
C++ without library 코드와 설명
코드
| |
코드 설명
- 헤더 파일 포함
#include <stdio.h>: 표준 입출력을 사용하기 위해 포함한다.
- 메인 함수 정의
int main() { ... }: 프로그램의 시작점이다.
- 테스트 케이스 처리
int T; scanf("%d", &T);: 테스트 케이스 수를 입력받는다.while (T--) { ... }: 테스트 케이스 수만큼 반복한다.
- 주식 데이터 처리
int N; scanf("%d", &N);: 주식 데이터의 일수를 입력받는다.long long totalProfit = 0;: 총 이익을 저장할 변수를 초기화한다.for (int i = 0; i < N; ++i) { ... }: 각 날에 대해 반복한다.int A, B, C; scanf("%d %d %d", &A, &B, &C);: 각 회사의 손익을 입력받는다.int maxProfit = A;: 최대 이익을 A로 초기화한다.if (B > maxProfit) maxProfit = B;: B와 비교하여 최대값을 갱신한다.if (C > maxProfit) maxProfit = C;: C와 비교하여 최대값을 갱신한다.if (maxProfit > 0) { totalProfit += maxProfit; }: 최대값이 양수이면 총 이익에 더한다.
- 결과 출력
printf("%lld\n", totalProfit);: 총 이익을 출력한다.
- 프로그램 종료
return 0;: 프로그램을 정상적으로 종료한다.
코드 동작 단계별 설명
- 입력 받기
- 표준 입력 함수를 사용하여 테스트 케이스 수 T를 입력받는다.
- 테스트 케이스 반복
- 각 테스트 케이스마다 다음을 수행한다.
- 주식 데이터의 일수 N을 입력받는다.
- 총 이익을 저장할 변수 totalProfit을 0으로 초기화한다.
- 각 테스트 케이스마다 다음을 수행한다.
- 일별 데이터 처리
- N일 동안 다음을 반복한다.
- 각 회사의 손익 A, B, C를 입력받는다.
- 최대값 maxProfit을 A로 초기화한다.
- B와 비교하여 더 큰 값을 maxProfit에 저장한다.
- C와 비교하여 더 큰 값을 maxProfit에 저장한다.
- maxProfit이 양수이면 totalProfit에 더한다.
- N일 동안 다음을 반복한다.
- 결과 출력
- 각 테스트 케이스마다 계산된 totalProfit을 출력한다.
Python 코드와 설명
코드
| |
코드 설명
- 테스트 케이스 처리
T = int(input()): 테스트 케이스 수를 입력받는다.for _ in range(T):: 테스트 케이스 수만큼 반복한다.
- 주식 데이터 처리
N = int(input()): 주식 데이터의 일수를 입력받는다.total_profit = 0: 총 이익을 저장할 변수를 초기화한다.for _ in range(N):: 각 날에 대해 반복한다.A, B, C = map(int, input().split()): 각 회사의 손익을 입력받는다.max_profit = max(A, B, C): 세 회사의 손익 중 최대값을 찾는다.if max_profit > 0: total_profit += max_profit: 최대값이 양수이면 총 이익에 더한다.
- 결과 출력
print(total_profit): 총 이익을 출력한다.
코드 동작 단계별 설명
- 입력 받기
- 표준 입력 함수를 사용하여 테스트 케이스 수 T를 입력받는다.
- 테스트 케이스 반복
- 각 테스트 케이스마다 다음을 수행한다.
- 주식 데이터의 일수 N을 입력받는다.
- 총 이익을 저장할 변수 total_profit을 0으로 초기화한다.
- 각 테스트 케이스마다 다음을 수행한다.
- 일별 데이터 처리
- N일 동안 다음을 반복한다.
- 각 회사의 손익 A, B, C를 입력받는다.
max(A, B, C)를 사용하여 최대값 max_profit을 찾는다.- max_profit이 양수이면 total_profit에 더한다.
- N일 동안 다음을 반복한다.
- 결과 출력
- 각 테스트 케이스마다 계산된 total_profit을 출력한다.
결론
이번 문제는 각 날마다 최대 이익을 가져다주는 주식을 선택하는 간단한 그리디 알고리즘으로 해결할 수 있었다. 매일의 데이터에서 최대값을 선택하고, 그 값이 양수인 경우에만 총 이익에 더하는 방식으로 문제를 풀었다. 이 과정에서 시간 복잡도는 **O(N)**으로 매우 효율적이다.
문제를 풀면서 입력 데이터를 어떻게 효율적으로 처리할지, 그리고 그리디 알고리즘의 적용 가능성을 확인하는 것이 중요하다는 것을 다시 한 번 느꼈다. 또한, 코드를 작성할 때 변수의 자료형에 주의하여 큰 수의 합산에서도 오버플로우가 발생하지 않도록 해야 한다.
앞으로도 다양한 문제에서 그리디 알고리즘을 적용할 수 있는지 고민해보고, 효율적인 알고리즘 설계에 집중해야겠다.
![Featured image of post [Algorithm] C++/Python 백준 13416번 : 주식 투자](/post/algorithm/2024-10-16-boj-13416/tmp_wordcloud_hu_60f534365f97d876.png)
![[Algorithm] C++/Python 백준 5342번 : Billing 다국어](/post/algorithm/2024-10-17-boj-5342/tmp_wordcloud_hu_823a5d86092c575a.png)
![[Algorithm] C++ 백준 14572번 : 스터디 그룹](/post/algorithm/2024-10-16-boj-14752/tmp_wordcloud_hu_610e4d5c3c0d3715.png)
![[Algorithm] C++/Python 백준 13416번 : 주식 투자](/post/algorithm/2024-10-16-boj-13416/tmp_wordcloud_hu_98f05467ce30f2e0.png)
![[Algorithm] C++/Python 백준 1384번 : 메시지](/post/algorithm/2024-10-16-boj-1384/tmp_wordcloud_hu_e30462bdc020717b.png)
![[Algorithm] C++/Python 백준 15025번 : Judging Moose](/post/algorithm/2024-10-16-boj-15025/tmp_wordcloud_hu_7a1ace6fcb543cc8.png)
![[Algorithm] cpp-python 백준 16993번: 연속합과 쿼리 (세그먼트 트리)](/post/algorithm/2025-09-16-boj-16993-maximum-subarray-queries-segment-tree-cpp-python-solution/wordcloud_hu_789f7bcec4a582b7.png)
![[Algorithm] C++/Python 백준 4655번 : Hangover](/post/algorithm/2024-10-17-boj-4655/tmp_wordcloud_hu_d531c6ea875b9a53.png)
![[Algorithm] C++ 백준 1031번: 스타 대결](/post/algorithm/2025-10-14-boj-1031-star-battle-cpp-solution/wordcloud_hu_f77f5f84ec32b33a.png)
![[Algorithm] cpp 백준 18186번: 라면 사기 (Large)](/post/algorithm/2025-09-04-boj-18186-ramen-buying-large-greedy-cpp-solution/wordcloud_hu_2d2533b219761dcf.png)
![[Algorithm] cpp 백준 10076번: 휴가 - 최적 풀이](/post/algorithm/2025-08-14-boj-10076-holiday-ioi-2014-cpp-solution/wordcloud_hu_b2d0e7fda43f1a4a.png)