import java.io.*;
import java.lang.reflect.Array;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.Arrays;
public class Main{
//dp[n][k]: 맨뒷자리수가 k이면서 자릿수는 n개인 수들의 개수를 의미
//dp[1][2]: 은 숫자 2를 의미한다. 자릿수는 1개이면서 맨뒷수는 k즉 2다
static long dp[][];
//입력받는 수 n을 의미한다.
static int n;
//문제를 재귀적으로 해결하는 함수를 만들었다.
//기록이 되기때문에 매우짧은시간내에 해결이 가능하다
public static long solve(int n, int k){
//아래 조건이 없으면 stackoverflow난다
//k에 대한 조건은 없어도된다 아래의 코드에서 알아서 잡아주기때문
//k가 너무커질려하는순간 = 9 에서 알아서 컷해줌
//k가 너무작아지려고하는순간 = 0에서 알아서 컷해줌
//그래서 우리는 n을 계속 감소시키다보면 n==1인곳에 도달할거고
//그곳은 기본값으로 지정해줬기때문에 무조건그 값을 return하고 재귀를끝내도록해준다
if(n == 1) return dp[n][k];
//dp에 값이 저장되어있는경우 그 값을 return해준다 대신 나눠서 리턴해준다
// 모두 더한다음에 나누는거나 각값을 나눈다음에 더하는것이나 같기떄문에 이같은연산이 가능하다
if(n==1&&k==9||dp[n][k]!=0) return dp[n][k]% 1000000000;
//k==0인 경우에는 규칙에서 보인 특성에 따라 자릿수를 낮추고 k번쨰의 개수를 리턴한다
//자릿수가하나작고, 9로끝나는 숫자들로 dp[n][k]에 해당하는 숫자를만들수있기대문이다
if(k==0) {
dp[n][k] = solve(n-1, 9);
return dp[n][k];
}
//1인 경우에 규칙을 살펴보면 자신보다 하나큰수로 자기자신을 만들수있다.
//이들은 모두 자기보다 작은수에 대해서 값을가져와서 채우는데
//n==1인 기본값이 채워져있어서 재귀적으로 이런작업이가능한것이다
else if(k==1){
dp[n][k] = solve(n-1, k+1);
return dp[n][k];
}
//9인 경우도 예외적으로 k+1, k-1로 처리할수없기때문에 아래와같이 직접숫자를넣어주었다
else if(k==9) {
dp[n][k] = solve(n-1, 8)+ solve(n-1, 0) ;
return dp[n][k];
}
//그외의 숫자들은 모두 아래와같은 규칙으로 적용이 가능하다
//값을 기록해야하기때문에 기록하는과정을빼먹지말자
else{
dp[n][k] = solve(n-1, k+1) + solve(n-1, k-1);
return dp[n][k];
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
dp = new long[n+1][10];
//초기화하는 작업
for(int i=0;i<10;i++){
dp[1][i] = 1;
}
//자릿수가 1개이면서 0으로끝나는 숫자는 없다
//0은 해당되지않는다
dp[1][0] = 0;
//solve(n,1)만 하면 숫자 1에 대해서만 조사하기때문에..
//모든숫자를 채워서 재귀탐색을하기위해선 0~9까지를 조사해야한다
for(int i=0;i<=9;i++){
solve(n,i);
}
//조사를 마친 후 배열에 저장된 값들을 모두 더해준다
long sum = 0l;
for(int i=0;i<10;i++){
sum += dp[n][i];
}
//너무커질수도있으니 나눠준다
bw.write(sum % 1000000000 +"");
bw.flush();
bw.close();
}
}
n은 자릿수
0~9는 0~9로끝나는 수
즉, 220은 4자리수이면서 0으로끝나는 수의 갯수를 의미한다
220은 n=4-1인 n=3의 모든값을 더한 결과와 같다.
n=2쪽이 좀더 이해하기 쉽다
(n=2,k=0)인 수는
(n=1,k=0)~(n=1,k=9)의 합과 같다.
import java.io.*;
import java.lang.reflect.Array;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.Arrays;
public class Main{
//
//
static long arr[][];
public static long solve(int n, int k){
//계속 n-1만하다보면 n이 음수가 돼버린다. 그에 대응하는 배열값은 없다
//멈춰주어야한다. 종료조건이 있어야한다
if(n<=0) return 0l;
//memorization을 통해 여기서 함수의 재귀를 멈춰준다
if(arr[n][k]!=0) return arr[n][k];
long sum = 0l;
//i는 k부터 9까지여야한다
//그러니까 가장 마지막수가 i라면 그 뒤의 수는 무조건 i보다 크거나 같아야한다는얘기다
for(int i=k;i<=9;i++){
long x = solve(n-1,i);
sum= (sum + x) % 10007;
}
arr[n][k] = sum;
//다 더한뒤에 나누는거나 중간중간 더하는과정에서 매번나누는거나 똑같다
return arr[n][k] % 10007;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(br.readLine());
//n+1인이유는 n=0인칸은 안쓸것이기때문이고
//10으로 써준이유는 0부터9까지수를 써줄것이기때문이다
arr = new long[n+1][10];
//가장 아랫단에 있을 수들을 초기화해주어야한다
//이값이 없으면 함수가 stackoverflow날것이다.
//함수가 더이상 호출못하게 끝맺음해주는부분이있어야한다
for(int i=0;i<=9;i++){
arr[1][i] = 1;
}
long sum =0l;
//solve를할때마다 n번쨰자릿수에서 i번째로 끝나는 수의 갯수가 출력된다
//해당 갯수를 모두 더하면 n번째자릿수의 오르막수를 구할 수 있다
for(int i=0;i<=9;i++){
sum = (sum + solve(n,i)) % 10007;
}
bw.write(sum%10007+"");
bw.flush();
bw.close();
}
}
이친수가 되기위해선
이친수 + 0
이거나
이친수 + 01
이여야한다
n자리 이친수를 구하기위해서
n-2자리이친수 + 0
과
-1자리 이친수 + 01
을 가져오면된다
즉, dp[n]=dp[n-2]+dp[n-1]
이 성립한다.
public static void solve(){
dp[0] = 1;
//원소 하나하나를 보고. 이 원소를 이전원소들과 비교하여 얼마나 큰지를 따져봐야한다
for(int i=1;i<arr.length;i++){
//일단 최소길이가 1이기때문에 1로 세팅해주었다
dp[i] = 1;
//i번째 이전원소에 대해. 첫번째원소부터 시작하여 만약에 i보다 큰값이여서 증가하는 수열에 포함될수있다면 포함시켜줘야한다
for(int k=0;k<i;k++){
//dp는 같을수도있다. 맨처음에 1로 초기화하기때문에 처음엔 같을수도있다. 하지만 일단 arr값이 크다면 업데이트해주어야하기때문에
//dp[i]>=dp[k]에 등호를 넣었다
//값은 내가 더 큰데 dp의 값, 즉 이전원소들이 만들어놓은 수열이 더 긴경우
//기존것에 합세한다
if(dp[i]<= dp[k] && arr[i] > arr[k]){
//기존것에 합세하는거기때문에 기존값+1을해준다
dp[i] = dp[k]+1;
}
}
}
public static int solve(){
//이런 이런 식의 부분 증가수열은 기준점을 잡은 후 기준점 이전까지의 수들과 비교하여 자신이 큰 경우만 dp 배열을 갱신해주면된다
// 증가 부분 수열 중에서 합이 가장 큰 것을 나타내는 변수 result
//수열의 합은 0보다는 클테니까 0을 초기화한다
int result =0;
//입력받은 수열의 갯수만큼 for문을 돌린다
for(int i=0;i<arr.length;i++){
//가장 합이 큰녀석에 대해서 이어나갈것이다
int max = 0;
//기준원소이전원소들을 모두탐색하는데, 나보다 값이 작은놈을 선택
//그리고 이원소의 sum의 값을 가져와서 max를 갱신한다
//max에는 가장 큰 합이 들어있을것이다.
for(int k=0;k<i;k++){
if(arr[k]<arr[i]){
max = Math.max(sum[k],max);
}
}
//for문을 다 돌고 나면 max에는 이전까지의 원소들중 가장 큰 값이 들어있을테고,
//sum에는 기존합+현재값을 갱신해준다
sum[i] = max+ arr[i];
//그리고 result는 sum의 값들중 최댓값을 return할것이기때문에
//겸사겸사 계산한다
result = Math.max(sum[i], result);
}
return result;
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Objects;
import java.util.StringTokenizer;
import static java.util.Objects.*;
public class Main{
static int arr[][];
static int sum[][];
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(br.readLine());
//삼각형에 대한 정보를 담을 arr배열
arr = new int[n][n];
//삼각형가장꼭대기에서 아래로부터 합을 저장할 sum배열
sum = new int[n][n];
//입력받는 부분
for(int i=0;i<n;i++){
String input[] = br.readLine().split(" ");
//1개,2개,3개....n개 이렇게 입력받을 것임
for(int k=0;k<=i;k++){
arr[i][k] = Integer.parseInt(input[k]);
}
}
//삼각형의 꼭대기는 (0,0)을의미하며, 합또한 자기자신이다.
sum[0][0] = arr[0][0];
//최솟값이 0이니 0을 다 합해도 -1보단 크다. 가장작은값보다 작아야하니 -1으로 선정하였다
int result = -1;
//이중포문이어도 입력 크기가 작아서 가능
//i=0부터시작하지않아도되는이유는. 삼각형의꼭대기를 코드윗부분에서 설정해주었기때문이다.
for(int i=1;i<n;i++){
//1개, 2개, 3개, n개.. 씩 즉, 삼각형의 한줄씩 보기위한 for문
for(int k=0;k<=i;k++){
//k==0이라는것은 삼각형의 가장왼쪽부분에 있다는사실, 이렇게되면 sum[i-1][k-1]에대한값을 구할 수 없어서
//아래와 같이 예외처리한다
if(k==0){
int tempMax = sum[i-1][k];
sum[i][k] = tempMax + arr[i][k];
}
//일반적인 경우라면 자기 윗부분 + 자기 왼쪽부분 중 최댓값을 선정해서 그 값과 자기자신을 더해주면된다.
//삼각형의 가장오른쪽에있는부분은 어차피 자기 윗부분이 0이 나올것이기때문에 알아서 무시되는것을 확인할 수 있다
else {
int tempMax = Math.max(sum[i - 1][k], sum[i - 1][k - 1]);
sum[i][k] = tempMax + arr[i][k];
}
}
}
//결과는 삼각형의 가장 마지막줄에서 가장 큰값을 선택하면된다
for(int k=0;k<n;k++){
result = Math.max(result, sum[n-1][k]);
}
bw.write(result+"");
bw.flush();
bw.close();
}
}
오해했던 점
스티커가 모두 찢어진다는게아니라 하나씩만 떼어지는 건 줄 알았다.
스티커가 모두 찢어지는것이라면. 내가 i번째 배열요소를 봤을때 그 요소는 이전 요소들과 어떤 관계가 있을지 생각한다.
화살표에 해당하는 두 지점에만 갈 수 있다.
A와 B는 갈 수 없는것이 아니지만, 문제조건상 최댓값을 찾고, 요소들엔 모두 양수가있을것이기때문에 그 이전 요소들을 무조건 들러주는것이 최댓값을 찾을 수 있게 해준다.=
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.Objects;
import java.util.StringTokenizer;
import static java.util.Objects.*;
public class Main{
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.parseInt(br.readLine());
for(int i=0;i<n;i++){
int x = Integer.parseInt(br.readLine());
//두줄, x개의 칸의 이차원 배열 선언
//이 배열안에는 초기 입력값이 들어갈것임
int arr[][] = new int[2][x];
//최댓값을 구해나갈 배열변수
//arr의 값을 보면서 dp[0][?]과 dp[1][?]의 값을 채워나갈것이다
int dp[][] = new int[2][x];
//입력받는 부분, 두줄을 입력받을 것이다
for(int k=0;k<2;k++){
String input[] = br.readLine().split(" ");
//x번만큼 띄어서 입력받기
for(int j=0;j<x;j++){
arr[k][j] = Integer.parseInt(input[j]);
}
}
//초깃값 세팅 해주어야 아래 for문이 예외없이 잘돌아감
dp[0][0] = arr[0][0];
dp[1][0] = arr[1][0];
for(int j=1;j<x;j++){
//이거for문 밖으로 빼면 배열 밖 범위 초과 < error뜸
if(j==1){
//일단 첫번째dp의 경우 j-2의 값이 없기때문에 다음과 같이 하나의 값으로만 더해준다
//즉, 자기값 + 자기 이전 대각선 값으로 dp를 세팅해준다
dp[1][1] = arr[0][0] + arr[1][1];
dp[0][1] = arr[1][0] + arr[0][1];
}
else{
//이전대각선 vs 이이전 대각선 중 더 큰 값 + 자기자신
//dp[0][?]과 dp[1][?]을 동시에 세팅해주어야한다
dp[0][j] = Math.max(dp[1][j-1], dp[1][j-2]) + arr[0][j];
dp[1][j] = Math.max(dp[0][j-1],dp[0][j-2]) + arr[1][j];
}
}
//계속 더해나가다보면 배열의 가장 끝 두 값 중 가장 큰 값으로 출력해주면된다
//가장 마지막은 어쨋든 가장 마지막끝에서 발생될것이기 때문
bw.write(Math.max(dp[0][x-1], dp[1][x-1])+"\n");
}
bw.flush();
bw.close();
}
}
처음에는 xooxoo와 ooxoox의경우의수만 세주면된다고 생각했다.
일단 한번선택할때 두개를 선택하는게 무조건 이득이라고생각했기떄문이다
oxooxoo이런선택지가 있다는것을 몰랐따.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.OptionalInt;
public class Main{
static int n;
static int wine[];
static int dp[];
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
wine = new int[n+1];
dp = new int[n+1];
for(int i=0;i<n;i++){
wine[i] = Integer.parseInt(br.readLine());
}
//예외처리
if(n==1){
bw.write(wine[0]+"\n");
bw.flush();
bw.close();
return;
}
if(n==2){
bw.write( wine[1]+wine[0]+"\n");
bw.flush();
bw.close();
return;
}
if(n==3){
bw.write(Math.max(Math.max(wine[0]+wine[1],wine[0]+wine[2]), wine[1]+wine[2])+"\n");
bw.flush();
bw.close();
return;
}
//초깃값 세팅
dp[0] = wine[0];
dp[1] = wine[1]+wine[0];
//2번쨰까지오는데 최댓값은
//0,1 이렇게 와인을 먹거나
//1,2 이렇게 와인 먹거나
//0,2 이렇게 와인먹는 세가지 경우 중 하나이다
dp[2] = Math.max(Math.max(wine[0]+wine[1],wine[0]+wine[2]), wine[1]+wine[2]);
//i-3이있기때문에 위에 예외처리 과정을 해주었따
for(int i=3;i<n;i++){
//oox : dp[i-1]
//xoo: dp[i-3]+wine[i-1]+wine[i]
//oxo: dp[i-2]+wine[i]
//왜 dp에 넣는 인덱스가 x의 위치-1인가요?
//x기준왼쪽이 최댓값을 알아서 선택했다고 가정하는것이다.
//만약에 모든경우엥서 dp[i-3]을 해주고 o인경우는 wine[]을 더해주고 이렇게 된다면
//앞에서 oo을 선택하고 뒤에서도 oo을 선택하여 3개이상이 될 가능성이있다.
//그래서 x이전의 처리는 알아서 3개가 안되도록 앞에게 맡기고
//그 이후의 처리만 하는것이다
int max = Math.max(Math.max(dp[i-2]+wine[i], dp[i-3]+wine[i-1]+wine[i]), dp[i-1]);
dp[i] = max;
}
bw.write(dp[n-1]+"\n");
bw.flush();
bw.close();
}
}
public class Main{
static int n;
static int card[];
static int dp[];
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
card = new int[n+1];
dp = new int[n+1];
String input[] = br.readLine().split(" ");
//card에 대한 정보를 입력받는다
//idx를 card갯수로 조회하고 싶어서 n+1만큼 선언
for(int i=1;i<=n;i++){
card[i] = Integer.parseInt(input[i-1]);
}
//기본 전략은 다음과 같다
//구하려는것: 개수 x를 가지는 카드가격의 최댓값
//개수가 예를들어 x라면. 1~x까지의 여러 조합을 통해
//1 x-1
//2 x-2 이런조합을 통해 합이 x인 것들중 최댓값을 dp에 저장한다
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i] = Math.max(dp[i-j] + card[j], dp[i]);
}
}
bw.write(dp[n]+"\n");
bw.flush();
bw.close();
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.OptionalInt;
public class Main{
static int n;
static int[] dp;
public static void solve(){
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
//dp[x]: x일 이전까지 일을 했다고 가정했을떄 x날에 받을 돈의 최댓값
//n일까지 일할테니까 dp[n+1]의값을 구하면된다
//문제를 쪼개서 생각해보면
//x일이전까지일을했고 + 지금 이일을했을때 그떄가서 받을 돈, 이일을 하지 않는다고 가정했을때 내가 받을 최댓값
//중에 최댃값을 매번 갱신해준다
//그리고 dp의 값은 이전의 최댓값을 그대로 끌고와야 계속 누적이 된다
dp = new int[n+2];
for(int i=1;i<=n;i++){
String input[] = br.readLine().split(" ");
int period = Integer.parseInt(input[0]);
int pay = Integer.parseInt(input[1]);
//값을 끌고오는 것
dp[i] = Math.max(dp[i-1], dp[i]);
//대상의 원래값(지난 idx에서 누군가가 더큰값으로 업데이트했을수도있으니) vs i번째날기준 i-1까지 일을했고, i번째날에 받을돈 + 이번에 내가 일을 하며 받을돈,
int target = period+i;
if(target<n+2) dp[target] = Math.max(dp[target], dp[i] + pay);
}
dp[n+1] = Math.max(dp[n], dp[n+1]);
bw.write(dp[n+1]+"");
bw.flush();
bw.close();
}
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.OptionalInt;
public class Main{
static int n;
static long dp[];
static long solve(int idx){
if(idx<=0) return 0;
if(dp[idx]!=0) return dp[idx];
//큰수부터 시작하기때문에 dp[idx-1]+1을넣으면 0에다 +1을 한 값을 넣게된다
//일단 여기서 부터 재귀호출을 하여서 값을 구해놓은 다음에 for문을 돌려야한다
//1. A만 추가하는경우
dp[idx] = solve(idx-1)+1;
//idx의 위치보다 3칸 왼쪽에 있는애부터 계속왼쪽으로 한칸씩 간다
//그래서 왼쪽으로 한칸 갈때마다 곱하는 수를 늘려준다
//아래의 식은 예제를 만들어서 식을 세웠다.
//2. Ctrl(복붙)하는 경우: 이경우는 세세하게 나눠보면
//세종류의 버튼을 누르는것과 세종류의 버튼을 이미 눌렀다면 버튼 하나만 눌러도되는경우가있다
//근데 이경우를 아래 for문으로 합칠 수 있다.
//solve(i):i번 버튼을 눌렀을때의 A의 최댓값
//세종류의 버튼을 이미 눌렀다고 가정하고 시작을해야한다. 그래야 두번쨰 복붙의 경우도 진행이 가능하니까
//그래서 3을빼주는것이다. 이미 버튼이 눌려졌다고 가정한다
//그리고 A의 갯수는 하나 줄이고 곱하는수(곱하는버튼)은 늘리면서 가장 큰 조합을 찾아서
//dp에 저장한다
for(int i=idx-3;i>=1;i--){
dp[idx] = Math.max(solve(i) * (idx-i-1), dp[idx]);
}
return dp[idx];
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
//예외처리
if(n==1) {
bw.write("1\n");
bw.flush();
bw.close();
return;
}
if(n==2){
bw.write("2\n");
bw.flush();
bw.close();
return;
}
dp = new long[n+1];
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
bw.write(solve(n)+"\n");
bw.flush();
bw.close();
}
}
아래의 직사각형이 물건이라고 가정할떄 다음과 같이 하면 최댓값을 구할 수 있을것이라고 생각했다. 근데 아래와 같이 로직을 짜게 되면
다음 예시에서 잘못된 답을 도출할 것이다.
3 5
3 4
2 1
1 100
104를 도출해야하는데 101을 도출한다.
그이유는 일단 감당할수있는 weight보다 합이 작으면 추가해주기때문이다.
추가해주는 값이 최대의 value를 보장한다고 말할수있는가?
없다.
import com.sun.jdi.request.BreakpointRequest;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.OptionalInt;
public class Main{
static int n;
static long dp[];
//가방안에 넣는 물건을 정의한 class
public static class Thing{
//무게
int weight;
//가치
int value;
Thing(int w, int v){
this.weight = w;
this.value = v;
}
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String input[] = br.readLine().split(" ");
int n = Integer.parseInt(input[0]);
int weight = Integer.parseInt(input[1]);
Thing[] things = new Thing[n];
for(int i=0;i<n;i++){
String input2[] = br.readLine().split(" ");
int w = Integer.parseInt(input2[0]);
int v = Integer.parseInt(input2[1]);
things[i] = new Thing(w,v);
}
ArrayList<Integer> resultList = new ArrayList();
for(int i=0;i<n;i++){
//매 반복마다 최대value를 구합니다
int max =0;
int currentWeight = 0;
//weight보다 작으면 가장왼쪽부터 더해나갑니다
if(things[i].weight +currentWeight <= weight) {
max = Math.max(things[i].value, max);
currentWeight += things[i].weight;
}
//가장왼쪽부터 weight보다 합계 무게가 적으면 더해나갑니다
for(int j=i+1;j<n;j++){
if(things[j].weight + currentWeight <= weight){
max += things[j].value;
currentWeight += things[j].weight;
}
}
resultList.add(max);
}
int max =0;
for(Integer i: resultList){
max = Math.max(i,max);
}
bw.write(max+"");
bw.flush();
bw.close();
}
}
아이템이 주르륵 나열되어있다고 생각하자. 그리고 아이템을 선택하거나 안할수있다.
그리고 선택을 하거나 안할때의 값을 생각해서 둘중에 더 큰것으로 매번 갱신한다면 최종결과를 얻을 수 있다. 하지만 이것을 재귀로한다면 시간초과가 날것이다. 일단 두개를 선택하는 경우에서도 2^n이나옴
dp[i] = dp[i-1]에 관한 식?
i만으로는 부족하다. 하나의 변수가 더있어야한다. 왜냐하면 idx가 -1이되면서 기준값이 되는 weight변수또한 변하기때문이다.
무게k에 들어갈수있는가치 v의 최댓값을 구해야한다.
v를 결과값이라고 생각해보고, 무게를 변수로 생각해보자.
또한 아이디어의 첫 시작이 i번째 물건을 챙길수도있고, 아닐수도있고니까
i와 k의 이차원배열로 만들고 그 결과값이 value여야한다
dp[i][w] = dp[i-1][w-wi]
이런식으로 변수 두개를 받는 배열이 필요하다dp[i][w]
: i까지 물건을봤을때의 value의 최댓값.weight는 현재 wo(nW)의 시간복잡도를 가지는것은 이해하겠으나 이게 다항함수가 아니라고한다.
왜냐하면 w는 값자체의 범위를 표현하는것이기때문에 값하나를표현하려면
값의개수가 n개라고 했을때 2^n = w이다 (왜지?)
w라는숫자가 들어올때 입력사이즈는 logW이다 (왜지?)
그러니까 o(n*2^n)
인것이다
public class Main{
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String input[] = br.readLine().split(" ");
int n = Integer.parseInt(input[0]);
int weight = Integer.parseInt(input[1]);
int dp[][] = new int[n+1][weight+1];
int value[][] = new int[n+1][2];
for(int i=1;i<=n;i++){
String input2[] = br.readLine().split(" ");
int w = Integer.parseInt(input2[0]);
int v = Integer.parseInt(input2[1]);
value[i][0] = w;
value[i][1] = v;
}
//0부터 시작하면 dp[i-1][w]에 접근할떄 예외처리를 해주어야해서
//1부터 시작하게끔 만들음
for(int i=1;i<=n;i++){
for(int w=1;w<=weight;w++){
int valueW = value[i][0];
if(w < valueW) dp[i][w] = dp[i-1][w];
else{
dp[i][w] = Math.max(dp[i-1][w], value[i][1]+dp[i-1][w-valueW]);
}
}
}
bw.write(dp[n][weight]+"");
bw.flush();
bw.close();
}
}
int형으로 배열을 선언하게 되면 값이 0인것들은 모두 무시하게된다. 0일수도있는데..
그럼 재귀호출이 계속쌓이는것이다. 이게 그렇게 문제가 되는줄은 모르겠는데 문제가 되나보다.. 이해가 잘 안가긴한다.
점화식을 보고 그대로 식을 세웠다. 하지만 왜 점화식을 저렇게 세울 수 있는지 잘모르겠다
다시꼭 풀어봐야겠다