📙 Algorithm Solving/Java
📙[Algo] BOJ2662. 기업 투자
혜덕hyeduck
2024. 9. 25. 19:18
https://www.acmicpc.net/problem/2662
문제 요약
- 만원 단위로 각 기업에 투자할 수 있다
- 돈을 투자하게 되면 얻게되는 이익도 있다.
- 투자액이 정해져 있고, 기업의 개수와 각 기업에 투자했을 때 얻는 이익이 주어질 때, 가장 많이 얻을 수 있는 투자방식과 그때의 이익금을 구하라
시간 제한
- 1초
입력
- 투자 금액 N과 투자 가능한 기업들 개수 M
- 1 ≤ N ≤ 300, 1 ≤ M ≤ 20
- N개의 줄에 투자액수와 각 기업이 투자가에게 주는 이익이 주어진다.
- 투자 금액은 항상 1~N
- 같은 투자금액이 두 번이상 주어지지 X ⇒ i번째 줄에 주어지는 투자 금액은 i-1만원
출력
- 얻을 수 있는 최대 이익 출력
- 각 기업에 투자한 액수 출력
접근법
- 재귀DP로 접근했고, 매개 변수로 현재 갖고 있는 금액 remain과 현재 가리키는 기업 번호 cur을 넘겼다.
- 즉, 매 케이스마다 현재 remain원이고, cur번째 기업을 가리킬 때 가장 최대로 얻을 수 있는 이익을 찾게된다.
- 따라서, 0원~reamin원까지 투자하는 케이스를 보게되므로, N^(remain*cur)만큼의 경우의 수를 살펴야 한다. ⇒ dp배열에 메모이제이션 수행
- 종료조건은 M개의 기업을 모두 탐방했을 때이므로 cur가 M이상일 때 종료했다.(기업 번호를 0번부터 시작했다)
- 또한, 이 문제에서 각 기업에 투자한 금액을 찾아야 해서, 바로 Math.max로 최댓값을 갱신하지 않았고, 현재까지 저장된 이익(ret)보다 클 경우에만, 최댓값 갱신후 log배열에 현재 투자한 금액을 저장했다.
- log배열은 remain원이 남았을 때, cur번 기업을 가리킬 때 투자한 금액을 저장하게 된다.
- 재귀를 다 돌고 난 뒤에 반환값은 최대이익이 되고, 각 기업에 투자한 금액을 알기 위해 log배열을 사용해야 한다.
- 이때, 우리가 탑다운으로 log배열에 기록했기 때문에,
- log[N][0]일 때, 0번째 기업에 투자한 금액이 sum이라면
- 그 다음 기업은 log[N-sum][1]…. 이런식으로 각 기업에 투자한 금액을 찾아가야한다.
- 이거는 재귀dp로 풀었기 때문에, N부터시작해서 각 케이스마자 가장 최적의 경우를 기록했다는 걸 생각해야한다…
- 즉, log[N][0]은 최대이익을 얻기 위해, 0번 기업에 투자한 금액이 저장될 것이고, 그 다음 1번 기업은 0번 기업에 투자한 금액을 뺀 나머지 금액에서 1번 기업의 투자 금액을 찾아야한다…
- 이때, 우리가 탑다운으로 log배열에 기록했기 때문에,
코드
import java.io.*;
import java.util.*;
public class Main {
static int N, M;
static int[][] arr;
static int[][] log;
static int[][] dp;
static int recur(int remain, int cur) {
// remain : 현재 갖고있는 금액
// cur : 가리키는 회사 번호
if (cur >= M) return 0;
if (dp[remain][cur] != -1) return dp[remain][cur];
int ret = 0, tmp;
for (int i = 0; i <= remain; i++) {
// i원 만큼 투자
tmp = recur(remain - i, cur + 1) + arr[i][cur];
if (ret < tmp) {
ret = tmp;
log[remain][cur] = i;
}
}
dp[remain][cur] = ret;
return ret;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
arr = new int[N + 1][M];
log = new int[N + 1][M];
dp = new int[N + 1][M];
for (int[] d : dp) {
Arrays.fill(d, -1);
}
for (int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine());
st.nextToken();
for (int j = 0; j < M; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
StringBuilder sb = new StringBuilder();
int ret = recur(N, 0);
sb.append(ret).append("\\n");
int sum = N;
for (int i = 0; i < M; i++) {
sb.append(log[sum][i]).append(" ");
sum -= log[sum][i];
}
System.out.println(sb);
}
}