일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 벡엔드
- 해시
- 네이버 부스트캠프 ai tech
- BJ
- jsp
- 프로그래머스
- 프림 알고리즘
- 웹 프로그래밍
- DP
- 소수
- mst
- SERVLET
- 부스트코스
- programmers
- Prim's Algorithm
- 백준
- 순열 알고리즘
- 브라우저
- mysql
- 정렬
- 크루스칼 알고리즘
- request
- 정렬 알고리즘
- dbms
- Kruskal's Algorithm
- 그리디
- 웹서버
- greedy
- 웹프로그래밍
- 다이나믹 프로그래밍
- Today
- Total
끵뀐꿩긘의 여러가지
백준 - 1436번, 1로 만들기 (sol.java) 본문
◎문제 링크
https://www.acmicpc.net/problem/1463
1463번: 1로 만들기
첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.
www.acmicpc.net
◎문제 파악:
할 수 있는 연산
- X가 3으로 나누어 떨어지면, 3으로 나눈다.
- X가 2로 나누어 떨어지면, 2로 나눈다.
- 1을 뺀다.
입력된 숫자가 1일 경우: 연산할 필요가 없으므로 0
입력된 숫자가 2일 경우:
1. X가 3으로 나누어 떨어지지 않으므로, 3으로 나누지 않는다.
2. X가 2로 나누어 떨어지므로, 2로 나눈다.
3. 1을 뺀다.
1은 실행할 수 없으므로, 최소값은 2로 나눈 경우(연산하면 1이 된다, 최종 연산수: 1)와
1을 뺀 경우(연산하면 1이된다, 최종 연산수: 1)의 최솟값이다.
최솟값 = 1
입력된 숫자가 3일 경우:
1. X가 3으로 나누어 떨어지므로, 3으로 나눈다.
2. X가 2로 나누어 떨어지므로, 2로 나눈다.
3. 1을 뺀다.
2는 실행할 수 없으므로, 최솟값은 3으로 나눈 경우(연산하면 1이 된다, 최종 연산수: 1)와
1을 뺀 경우(연산하면 2가 된다, 2의 최소 연산 값이 1이므로 최종 연산수 1+1 = 2)의 최솟값이다.
최솟값 = 1
입력된 숫자가 4일 경우:
1. X가 3으로 나누어 떨어지지 않으므로, 3으로 나누지 않는다.
2. X가 2로 나누어 떨어지므로, 2로 나눈다.
3. 1을 뺀다.
1은 실행할 수 없으므로, 최솟값은 2로 나눈 경우(연산하면 2가 된다, 2의 최소 연산 값이 1이므로 최종 연산수 1+1 = 2)와 1을 뺀 경우(연산하면 3가 된다, 3의 최소 연산값이 1이므로 최종 연산수 1+1 = 2)의 최솟값이다.
최솟값 = 2
이런 느낌으로 DP를 사용하여, 2부터 원하는 숫자까지, 1,2,3번 연산 중 가능한 것을 실행하고, 전에 저장된 계산 값을 이용하여 숫자의 최소 연산 값을 구해주면 된다.
◎코드 구현
최초 풀이:
문제점:
나누는 것을 중요히 생각하여, 3으로 또는 2로 나눠질 때까지 빼주는 연산을 시행하였다.
하지만, 이미 이전 배열에 뺸 연산이 적용되어 있으므로 (숫자 4에 관련된 최소 연산 값은 5에서 -1을 한 값의 최소 연산 값이다) 중복하여 계산한 꼴이 되어버렸다.
package ProgrammersBj.MakeItOne;
public class Bj_MakeItOne {
int[] arr; // DP 각 숫자를 1로 만들기 위한 최소 연산 수를 저장한 배열
public void solution(int num) {
if(num==1) {
System.out.println(0);
return; // 1은 그 자체로 1
}
if(num==2 || num==3) {
System.out.println(1);
return; // 2/2 = 1, 3/3 = 1
}
arr = new int[num+1];
arr[1] = 0;
arr[2] = 1;
arr[3] = 1;
/*
* i가 3으로 나눠지면 추가연산 x
* i-1이 3으로 나눠지면 -1을 해줘야하기 때문에 추가연산 = 1
* i-2이 3으로 나눠지면 -2을 해줘야하기 때문에 추가연산 = 2
*
* i가 2로 나눠지면 추가연산 x
* i-1이 2로 나눠지면 -1을 해줘야하기 때문에 추가연산 = 1
*
* i를 3의 배수나 2의 배수로 만들어 2로 나누는것과 3으로 나누는 것중
* 어떤 연산이 가장 작은 연산값을 가지는지 파악
*
* ex. 10 = 2의배수 -> arr[10/2],
* 10-1 => 3의 배수 -> arr[9/3] +1
* 을 비교하여 작은 값을 저장
*/
for(int i = 4; i<=num; i++) {
if(i%3 ==0) {
if(i%2==0) { // i가 2로 나눠지면
arr[i] = Math.min(arr[i/3], arr[i/2]);
}else { // i-1이 2로 나눠지면
arr[i] = Math.min(arr[i/3], arr[(i-1)/2]+1);
}
}else if(i%3 ==1) {
if(i%2==0) {
arr[i] = Math.min(arr[(i-1)/3]+1, arr[i/2]);
}else {
arr[i] = Math.min(arr[(i-1)/3]+1, arr[(i-1)/2]+1);
}
}else {
if(i%2==0) {// i-2이 3으로 나눠지면
arr[i] = Math.min(arr[(i-2)/3]+2, arr[i/2]);
}else {
arr[i] = Math.min(arr[(i-2)/3]+2, arr[(i-1)/2]+1);
}
}
arr[i]++; //2또는 3으로 나눈 연산 횟수 추가
}
System.out.println(arr[num]);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Bj_MakeItOne sol = new Bj_MakeItOne();
sol.solution(107);
}
}
개선한 풀이:
package ProgrammersBj.Bj_MakeItOne;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class BJ_Improved_solution {
public void solution(int num) {
if (num == 1) {
System.out.println(0);
return; // 1은 그 자체로 1
}
int[] arr = new int[num + 1];
arr[1] = 0;// 1은 그 자체로 1
for (int i = 2; i <= num; i++) {
if (i % 3 == 0) {
if (i % 2 == 0) {
// 2로도 3으로도 나눠지는 경우
// 2로 나눈 값, 3으로 나눈 값, -1한 값 중 최소
arr[i] = 1 + Math.min(arr[i / 3], Math.min(arr[i / 2], arr[i - 1]));
} else {
// 3으로 나눠지는 경우
// 3으로 나눈 값, -1한 값 중 최소
arr[i] = 1 + Math.min(arr[i / 3], arr[i - 1]);
}
} else {
if (i % 2 == 0) {
// 2으로 나눠지는 경우
// 2으로 나눈 값, -1한 값 중 최소
arr[i] = 1 + Math.min(arr[i / 2], arr[i - 1]);
} else {
arr[i] = 1 + arr[i - 1];
}
}
}
System.out.println(arr[num]);
}
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n=Integer.parseInt(br.readLine());
BJ_Improved_solution sol = new BJ_Improved_solution();
sol.solution(n);
}
}
◎다른 사람의 풀이
package ProgrammersBj.Bj_MakeItOne;
import java.util.Scanner;
public class Bj_Others_Solution {
@SuppressWarnings("resource")
public static void main(String[] args) {
int N = new Scanner(System.in).nextInt(), dp[] = new int[N + 1];
for (int i = 2; i <= N; ++i)
/*
* 기본적으로 작동 알고리즘은 같지만, 삼항 연산자를 활용하여 획기적으로 짧게 코드를 구현했다.
*/
dp[i] = Math.min(dp[i - 1], Math.min(i % 3 == 0 ? dp[i / 3] : N + 1, i % 2 == 0 ? dp[i / 2] : N + 1)) + 1;
System.out.println(dp[N]);
}
}
◎github codes:
jerry-ryu/java_problemsolving_algorithm
solving problems and learning algorithm using java - jerry-ryu/java_problemsolving_algorithm
github.com
'JAVA > 문제풀이 - 프로그래머스' 카테고리의 다른 글
백준 - 2156번, 포도주 시식 (sol.java) (0) | 2021.05.30 |
---|---|
백준 - 10844번, 쉬운 계단 수 (sol.java) (0) | 2021.05.30 |
프로그래머스 - 단속카메라 (sol.java) (0) | 2021.05.26 |
프로그래머스 - 섬 연결하기 (sol.java) (0) | 2021.05.24 |
프로그래머스 - 구명보트 (sol.java) (0) | 2021.04.28 |