티스토리 뷰
[SWEA 1859 / JAVA] 백만 장자 프로젝트
문제: https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5LrsUaDxcDFAXc&
25년 간의 수행 끝에 원재는 미래를 보는 능력을 갖게 되었다. 이 능력으로 원재는 사재기를 하려고 한다.
다만 당국의 감시가 심해 한 번에 많은 양을 사재기 할 수 없다.
다음과 같은 조건 하에서 사재기를 하여 최대한의 이득을 얻도록 도와주자.
1. 원재는 연속된 N일 동안의 물건의 매매가를 예측하여 알고 있다.
2. 당국의 감시망에 걸리지 않기 위해 하루에 최대 1만큼 구입할 수 있다.
3. 판매는 얼마든지 할 수 있다.
예를 들어 3일 동안의 매매가가 1, 2, 3 이라면 처음 두 날에 원료를 구매하여 마지막 날에 팔면 3의 이익을 얻을 수 있다.
풀이:
문제를 분석해본 결과 다음과 같이 중요 포인트를 정리할 수 있었다.
- 첫째날이 최고 매매가이고 다음날로 갈수록 금액이 적어지는, 우하향 직선그래프를 하고 있다면 아무것도 사지 않아야 한다. (10 8 3 2 이런식)
- 그게 아니라면 최고 매매가를 1번째 체크포인트로 두고 그 전날까지 금액이 얼마든 모두 매입한다. 매입한 것을 모두 최고가에 판다.
- 최고 매매가 이후 배열에서 또 2번째 최고 매매가를 구한다. 1번째 최고 매매가 다음날부터 2번째 최고 매매가 전날까지 또 금액이 얼마든 모두 매입하고, 매입한 것을 2번째 최고가에 판다.
- N일이 다 끝날 때까지 위를 반복한다.
예를 들어
3 8 9 2 1 14 5 2 9 1
이런 식이라면
14원일 때까지 모두 매입한다음 (3 8 9 2 1원에 매입) 그걸 모두 14원에 팔고, 또 5 2원에 매입한걸 9원에 파는 것이 가장 큰 수익을 낼 수 있다.
이 문제를 해결하기 위해 다음과 같이 코드를 구상하였다.
1. N일 동안의 매매가를 배열로 입력받는다.
2. 전체 배열의 최댓값을 파악한다.
3. a[최대값의 위치] 전까지 모두 구매한다. 만약 최댓값이 현재위치(배열의 처음)일 경우 그냥 넘어간다.
4. 다시 a[최대값의 위치] 이후 매매가 중 최댓값을 파악한다.
5. 다시 a[2번째 최댓값의 위치]까지 모두 구매한다. 만약 최댓값이 현재위치(남은 배열의 처음)일 경우 그냥 넘어간다.
6. 배열의 끝까지 반복한다.
7. 계산한 수익금을 출력한다.
**이때 test case 7/10으로 통과되는 경우**
출력할 총 순이익을 Long 형으로 선언해야 한다.
int로 할 경우 오류가 발생한다.
코드:
import java.util.Scanner;
import java.io.FileInputStream;
class Solution
{
public static void main(String args[]) throws Exception
{
Scanner sc = new Scanner(System.in);
int T;
T=sc.nextInt();
/*
여러 개의 테스트 케이스가 주어지므로, 각각을 처리합니다.
*/
for(int test_case = 1; test_case <= T; test_case++)
{
int a = sc.nextInt();
int arr[] = new int[a]; // 매매값 배열
for (int i = 0; i < a; i++) {
arr[i] = sc.nextInt();
}
int max = 0; // 최댓값
int maxloc = 0; // 최댓값의 위치 a[maxloc]
Long profit = 0L; // 출력할 전체 순이익 **중요** int로 하면 에러발생
int currloc = 0; // 현재 위치 a[currloc]
while (currloc < a) { // 현재 위치가 배열의 끝일 때까지 반복한다
for (int i = currloc; i < a; i++) { // 현재 위치부터 끝까지의 최댓값 조사
if (arr[i] > max) {
max = arr[i]; // 최댓값과 최댓값 위치 저장
maxloc = i;
}
}
if (maxloc != currloc) { // 최댓값이 현재 위치가 아니라면 (현재 위치일 경우 구매하지 않아야 하니 pass)
int sum = 0; // 총 매입 금액을 저장할 변수
int count = 0; // 총 매입 개수
for (int i = currloc; i < maxloc; i++) { // 현재 위치부터 최댓값 전날까지
sum = sum + arr[i]; // 총 매입 금액을 더해간다
count++; // 총 매입 개수를 더해간다
}
profit = profit + (arr[maxloc]*count) - sum;
// 현재 순이익 = 이전에 계산한 순이익(초기값 0) + 판매 금액(최고 매매가) * 판매 개수 - 매입 금액
}
currloc = maxloc + 1; // 현재 위치를 최댓값 다음날로 업데이트 (그 다음날부터 또 두번째 최댓값 조사해야 하니까)
max = 0; // 최댓값 초기화
}
System.out.printf("#%d ", test_case);
System.out.println(profit);
}
}
}
코드 길이도 시간도 단축시킬 수 있는 더 나은 방법이 분명히 있는데.....
내 스스로 해결할 수 있는 코드는 이게 최선이다
'백준 > java' 카테고리의 다른 글
[백준 2563 / JAVA] 색종이 (2) | 2024.11.15 |
---|---|
[백준 2566 / JAVA] 최댓값 (0) | 2024.11.14 |
[백준 2738 / JAVA] 행렬 덧셈 (0) | 2024.11.14 |
[백준 9086 / JAVA] 문자열 (1) | 2024.11.14 |
[백준 2743 / JAVA] 단어 길이 재기 (0) | 2024.11.14 |
- Total
- Today
- Yesterday
- 코딩테스트
- swea
- 컨페티
- 굿노트스티커
- 포토샵png
- 스티커png
- 목업적용
- 포토샵
- 굿노트png
- 포토샵목업
- 컨페티png
- 삼성코테
- 굿노트
- 컨페티스티커
- 자바
- 다꾸
- 백준
- 티스토리챌린지
- 오블완
- EOF
- 굿노트다꾸
- 무료목업사이트
- 굿노트사용법
- 백준 #C++
- 목업
- 굿노트스티커자르기
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |