2차원 배열을 처음부터 끝까지 돌면서 위와 같이 이동만 해주며 DP 테이블을 채워주면 된다.
따로 방문여부를 기록하지 않고 DP 테이블의 값이 0인지 아닌지로
확인하려 했는데 정점의 값이 음수인 경우도 있어서 합이 0일 때가 있을 수 있기 때문에
따로 방문 여부를 기록할 불리언 배열을 사용했다.
각 정점(i, j)에서 갈 수 있는 정점들을 방문하며
처음 방문한 정점(x, y)이면 방문 여부를 참으로 바꾸고,
(x, y)의 DP 테이블에 (i, j) 테이블의 값 + 현재 정점의 값을 기록하고
이미 방문한 정점이라면 이미 기록된 값과 새로운 값 중 더 작은 값을 기록한다.
목적지까지 테이블을 다 채운 후에 목적지의 값을 출력해주면 된다.
풀이
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder sb = new StringBuilder();
int[] dx = {0, 1, 1, 1};
int[] dy = {1, -1, 0, 1};
int tc = 1;
while (true) {
int n = Integer.parseInt(br.readLine());
if (n == 0) break;
int[][] arr = new int[n][3];
int[][] dp = new int[n][3];
boolean[][] isVisited = new boolean[n][3];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < 3; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
dp[0][1] = arr[0][1];
isVisited[0][1] = true;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 3; j++) {
if (i == 0 && j == 0) continue;
if (i == n - 1 && j == 1) {
sb.append(tc++).append(". ").append(dp[i][j]).append("\n");
break;
}
for (int dir = 0; dir < 4; dir++) {
int x = i + dx[dir];
int y = j + dy[dir];
if (y < 0 || x >= n || y >= 3) continue;
if (isVisited[x][y]) {
dp[x][y] = Math.min(dp[x][y], dp[i][j] + arr[x][y]);
} else {
isVisited[x][y] = true;
dp[x][y] = dp[i][j] + arr[x][y];
}
}
}
}
}
System.out.println(sb);
}
}
다시 1원만 사용한 경우, 1원과 2원을 사용한 경우, 세 가지 동전을 모두 사용한 경우로
경우의 수가 몇 개인지 정리해보면 다음과 같다. (0번 인덱스는 1이다.)
1
2
3
4
5
6
7
8
9
10
1
1
1
1
1
1
1
1
1
1
1
1,2
1
2
2
3
3
4
4
5
5
6
1,2,5
1
2
2
3
4
5
6
7
8
10
1원 동전으로는 값만큼 동전을 사용하면 모든 값을 만들 수 있기 때문에 모두 한 가지일 것이니 넘어가고
2원까지 추가로 사용해 n원을 만드는 경우를 먼저 생각해보겠다.
2원을 사용해서 2원 미만의 값은 당연히 만들 수 없으니
미만의 값들은 이전의 값을 그대로 사용하고 넘어가면 되고
2원 이상부터는 2원 동전을 사용할 수 있으니 값이 달라질 것이다.
위의 표에서 1원과 2원을 사용해 2원을 만드는 경우를 살펴보면
(1원으로 2를 만드는 경우인 1) + (2원으로 2 - 2원을 만드는 경우인 1) = 2가 되고
10원을 만드는 경우를 살펴보면
(1원으로 10원을 만드는 경우인 1 + 2원으로 (10 - 2)원을 만드는 경우인 5 = 6이 된다
이제 5원 동전까지 사용하는 경우도 마찬가지로
5원 이상부터 테이블의 값을 변경해주면 되고
10원을 만드는 경우를 살펴보면
(1원과 2원으로 10원을 만드는 경우인 6) + (5원으로 10 - 5원을 만드는 경우인 4) = 10이 된다.
점화식으로 정리하면 다음과 같다. (i는 목표가치, j는 현재 동전의 가치)
dp[i] = dp[i] + dp[i-j]
이때 dp[0] = 1로 초기화 해주어야
동전의 가치가 K인 경우를 처리할 수 있고
동전의 가치 이상의 dp 테이블을 수정할 때 처음에 dp[0]을 호출할 일이 있기 때문에
이를 0인 초기값으로 냅둬두면 테이블의 값이 변하지 않는다.
풀이
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
int[] dp = new int[k + 1];
dp[0] = 0;
for (int i = 0; i < n; i++) {
int coin = Integer.parseInt(br.readLine());
for (int j = coin; j <= k; j++) {
dp[j] += dp[j - coin];
}
}
System.out.println(dp[k]);
}
}
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] dp = new int[n + 1];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++) {
dp[i] = Integer.parseInt(st.nextToken());
for (int j = 1; j <= i; j++) {
dp[i] = Math.max(dp[i], dp[j] + dp[i - j]);
}
}
System.out.println(dp[n]);
}
}
한 자리의 경우 : 1 두 자리의 경우 : 11, 00 세 자리의 경우 : 111, 100, 001 네 자리의 경우 : 1111, 1100, 1001, 0011, 0000 다섯 자리의 경우 : 11111, 11100, 11001, 10011, 10000, 00111, 00100, 00001
각 자릿수 별로 경우의 수를 적어보면 위와 같다.
우리가 사용할 수 있는 숫자는 한 자리인 1과 두 자리인 00 두 가지만 있는데
만약 여섯 자리의 수를 만들어야 한다 가정하면
첫자리에 1이 오면 그 뒤에는 다섯 자리의 수가 올 수 있을 테니
기존에 구해둔 다섯 자리의 경우만큼 만들 수 있을 것이고
첫자리에 00이 오면 그 뒤에는 네 자리의 수가 올 수 있으니
기존에 구해둔 네 자리의 경우만큼 만들 수 있을 것이다.
결국 1로 시작하는 경우와 00으로 시작하는 경우를 합쳐주면
n자리의 수를 만들 수 있는 경우의 수를 구할 수 있다.
점화식을 정리하면
첫자리에 1이 오는 경우는 (n-1)자리의 경우의 수가 되고
첫 자리에 00이 오는 경우는 (n-2)자리의 경우의 수가 되니
f(n) = f(n-1) + f(n-2) 가 된다.
풀이
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] arr = new int[1000001];
arr[1] = 1;
arr[2] = 2;
for (int i = 3; i <= n; i++) arr[i] = (arr[i - 1] + arr[i - 2]) % 15746;
System.out.println(arr[n]);
}
}