일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- replace()
- 프로그래머스
- 백준 2467번 용액 자바 - 이분탐색
- 백준 1647번 도시 분할 계획 - java
- StringTokenizer
- Stack
- 백준 14938번 서강그라운드
- dp
- Java
- toUpperCase
- map
- 최소 힙 1927
- 백준 1043번 거짓말 - java 분리 집합
- hash
- 백준 1541
- ac 5430번
- kotlin
- 백준 3190번
- HashSet
- 백준 2473번 세 용액 - java
- 18111번 마인크래프트 - java 구현
- append
- 백준 1197번 최소 스패닝 트리 - java
- mysql hy000 에러
- 코틀린기초
- HashMap
- 프로그래머스 자바
- 백준 1806번 부분합 java
- 프로그래머스 java
- StringBuilder
- Today
- Total
말하는 컴공감자의 텃밭
백준 - 1463번 1로 만들기 <실버 3> - 자바 DP 본문
처음엔 간단하게 생각했다.
초기값을 정하고, 연산 경우의 수를 따져서 간단하게 로직을 작성했었다.
가능한 큰 수인 3으로 나누는 경우가 좋을 것이라 판단했고, -1의 경우도 있기에 X % 3 == 1이면 2의 배수여도 먼저 -1 후 3을 나누는게 나을 거라고 판단했었다.
X가 10이라면
10 -> 5 -> 4 -> 2-> 1
10 -> 9 -> 3 -> 1
이런 차이도 있기 때문에 저런 로직을 추가했었다.
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 | import java.util.*; public class Main { public static void main(String[] args){ //input Scanner sc = new Scanner(System.in); int X = sc.nextInt(); int answer = 0; //logic while(true) { if(X == 1) { break; }else if(X % 3 == 1) { X -= 1; }else if (X % 3 == 0) { X /= 3; }else if (X % 2 == 0) { X /= 2; }else X -= 1; answer ++; } //output System.out.printf("%d",answer); } } | cs |
<기존 코드>
가볍게 틀려주면서 반례를 고민해 봤는데
700 -> 699 -> 233 -> 232 -> 231 -> 77 -> 76 -> 75 -> 25 -> 24 -> 8 -> 4 -> 3 -> 1
700 -> 350 -> 175 -> 174 -> 58 -> 29 -> 28 -> 14 -> 7 -> 6 -> 2 -> 1
당연히 이런 반례들이 나타났다.
그럼 Math.min를 사용해서 가장 적은 경우의 수를 찾아보려 했고, DP를 이용하려 했다
6으로 나눠지는 경우도 결국 2,3으로 나누는 경우와 1을 뺀 경우를 비교하는 것과 같기 때문에 배제했다.
dp [] 배열을 초기화하고, X가 1,2,3일 때 각각 0,1,1을 초기값으로 주었다.
이후 반복문을 진행하면서, dp[i -1] +1 로 값을 정해주고(이전 값에서 -1하면 한번 더 연산되기 때문에),
2로 나눠지거나 3으로 나눠지면 i/2 +1또는 i/3 +1와 비교해서 더 작은 값을 dp[i]에 넣어 주면
dp[]에는 X 이하의 모든 수가 배열에 정리가 된다.
ex) dp[10] 이라면
dp [4] = 2, Math.min( 2 , dp[2] +1 ) -> 2
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 |
dp [5] = 3
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 | 3 |
dp [6] = 4, Math.min( 4 , dp[3] +1 ) -> 2
dp [6] = 4, Math.min( 4 , dp[2] +1 ) -> 2
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 | 3 | 2 |
dp [7] = 3,
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 | 3 | 2 | 3 |
dp [8] = 4, Math.min( 4 , dp[4] +1 ) -> 3
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 | 3 | 2 | 3 | 3 |
dp [9] = 4, Math.min( 4 , dp[3] +1 ) -> 2
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 | 3 | 2 | 3 | 3 | 2 |
dp [10] = 3, Math.min( 3 , dp[5] +1 ) -> 3
dp[1] | dp[2] | dp[3] | dp[4] | dp[5] | dp[6] | dp[7] | dp[8] | dp[9] | dp[10] |
0 | 1 | 1 | 2 | 3 | 2 | 3 | 3 | 2 | 3 |
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 | import java.util.*; public class Main { public static void main(String[] args){ //input Scanner sc = new Scanner(System.in); int X = sc.nextInt(); int []dp = new int[X+1]; // dp[]는 X를 1로 만드는 최소한의 수 배열 dp[1] = 0; // 초기값 설정. dp[2] = 1; dp[3] = 1; //logic for(int i=4; i<= X; i++) { dp[i] = dp[i-1] + 1; // 이전보다 + 1 if(i % 2 == 0){ // 2로 나누어 진다면. dp[i] = Math.min(dp[i], dp[i/2] + 1); // i/2 +1과 비교해서 대입. } if(i % 3 == 0) { // 3으로 나누어 진다면 dp[i] = Math.min(dp[i], dp[i/3] + 1); // i/3 +1과 비교해서 대입. } } //output System.out.print(dp[X]); } } | cs |
간단한데 이상하게 오래 걸린 문제였다,, 완전탐색 방식이 어색하기도 했고, '다른방법이 있겠지~' 싶어서 재귀도 써보고 수학적으로 다른게 있나..? 해서 규칙 찾다가 더 오래걸린 문제였다.
** 수정 - 이클립스에선 잘 작동했는데
이게 뭐람 했는데 1보다 작으면 배열 초기화에 있어서 오류가 발생했다.
X 조건을 추가~, 또는 초기값이 0이므로 그냥 없어도 무방했다.
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 | import java.util.*; public class Main { public static void main(String[] args){ //input Scanner sc = new Scanner(System.in); int X = sc.nextInt(); int []dp = new int[X+1]; // dp[]는 X를 1로 만드는 최소한의 수 배열 if(X > 1) { // X가 1보다는 커야 배열이 성립. dp[0] = 0; dp[1] = 0; dp[2] = 1; dp[3] = 1; } //logic for(int i=2; i<= X; i++) { dp[i] = dp[i-1] + 1; // 이전보다 + 1 if(i % 2 == 0){ // 2로 나누어 진다면. dp[i] = Math.min(dp[i], dp[i/2] + 1); // i/2 +1과 비교해서 대입. } if(i % 3 == 0) { // 3으로 나누어 진다면 dp[i] = Math.min(dp[i], dp[i/3] + 1); // i/3 +1과 비교해서 대입. } } //output System.out.print(dp[X]); } } | cs |
'알고리즘 > Backjoon - Java' 카테고리의 다른 글
백준 29774 케이크 자르기 게임 (small) - java 에드훅 (0) | 2023.09.15 |
---|---|
백준 10815번 숫자카드 <실버5> - 자바 java 이분탐색, HashSet (0) | 2023.08.03 |
백준 13335 트럭 <실버 1> - 자바 Queue (0) | 2023.07.20 |
백준 1152 단어의 개수 <브론즈 2> - 자바 StringTokenizer (0) | 2023.07.18 |
백준 28278 스택2 <실버4> - 자바 Stack (0) | 2023.07.13 |