알고리즘/문제

(22.03.18) (Baekjoon) 12101. 1,2,3 더하기 2

Job_E 2022. 3. 19. 02:17

https://www.acmicpc.net/problem/12101

 

12101번: 1, 2, 3 더하기 2

n을 1, 2, 3의 합으로 나타내는 방법 중에서 사전 순으로 k번째에 오는 것을 출력한다. k번째 오는 식이 없는 경우에는 -1을 출력한다.

www.acmicpc.net

1,2,3 더하기는 1~9 시리즈까지 있다. 이번엔 그 두번째 문제다.

1번 문제가 주어진 숫자를 1,2,3으로 만들 수 있는 경우의 수를 구하는 문제라고 한다면,

이번 문제는 n과 m이 주어진다 했을 때, n의 숫자를 1,2,3으로 만들 수 있는 경우들 중 m번째 경우를 구하는 문제다.

이때, 각 셈은 사전 순으로 주어진다.

ex ) 4의 경우

1 + 1 + 1 + 1

1 + 1 + 2

1 + 2 + 1

1 + 3

2 + 1 + 1

2 + 2

3 + 1

의 순서를 의미한다.

즉,n = 4, m = 1이라 하면 1+1+1+1이 나와야 한다.

 

DP가 으레 그렇듯 작은 문제로 쪼개서 접근하자.

 

1) 각 수의 셈을 어떻게 순서대로 정렬할 것인가

일단 이전 문제는 int가 나와야 하는 것과 달리 String이 나와야 한다.

그렇기에 1번 문제에서 dp[i][j] 라 하면 dp[i-1]에서 영향을 받듯이 이 문제에서도 그렇게 될 수 있게 만들어 줘야 한다.

1-1) 일단 기본적으로 생각할 수 있은 값을 보면,

1 => 1

2 => 1+1, 2

3 => 1+1+1, 1+2, 2+1, 3 이 있는데

 

이 기본 값을 이용해서 4부터 차근차근 채워나가야 한다.

이전 문제에서 알 수 있었듯

4 의 경우로 또 생각하면

1로 시작하고 뒤에 3을 만드는 경우가 올 수 있고

2로 시작하고 뒤에 2를 만드는 경우가 올 수 있으며

3으로 시작하고 뒤에 1로 만드는 경우가 올 수 있다.

1,2,3으로써 사전 순서가 성립되기 때문에 이를 구현해주기만 하면 된다.

 

 

2) n 과 m에 대응하는 셈을 어떻게 구현할 것인가.

특정 요소 안에 자연스럽게 값을 추가해줘야 하기 때문에 ArrayList를 활용하면 된다.

ArrayList list = new ArrayList[n+3];
		
		for (int i = 0; i < n+3; i++) {
			list[i] = new ArrayList<String>();
		}
		// List 1에 해당하는 값을 집어넣음
		list[1].add("1");
		
		// List 2에 해당하는 연산을 집어넣음
		list[2].add("1+1");
		list[2].add("2");
		// List 3에 해당하는 연산을 집어넣음
		list[3].add("1+1+1");
		list[3].add("1+2");
		list[3].add("2+1");
		list[3].add("3");

 

우선 n보다 3 많은 크기의 ArrayList를 선언해준 후, 1,2,3에 해당하는 기본 셈들을 넣어준다.

for (int i = 4; i <= n; i++) {
			for (int j = 1; j <= 3; j++) {
				for (String s : list[i-j]) { //i = 4 => j = 1 
//					ArrayList[i-1] 에 있는 수식에 +1을 (ex i == 4, j == 1 => ArrayList[4-1]에 +1)
//					 ArrayList[i-2] 에 있는 수식에 +2을 (ex i == 4, j == 2 => ArrayList[4-2]에 +2)
//					 ArrayList[i-3] 에 있는 수식에 +3을 (ex i == 4, j == 2 => ArrayList[4-3]에 +3)
					list[i].add(j + "+" + s); 
				}
			}
		}

이후 위에서 설명했듯이 4번부터 새로 값을 집어넣기 사작하여 

ArrayList[i-1] 에 있는 수식에 +1을 (ex i == 4, j == 1 => ArrayList[4-1]에 +1)
ArrayList[i-2] 에 있는 수식에 +2을 (ex i == 4, j == 2 => ArrayList[4-2]에 +2)
ArrayList[i-3] 에 있는 수식에 +3을 (ex i == 4, j == 2 => ArrayList[4-3]에 +3)

의 방식으로 값을 집어넣으면 된다.

list[i].add(j + "+" + s)

앞의 숫자가 1,2,3 중 하나가 먼저 오면 된다.

 

전체 코드(Java)

더보기
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;

public class Main {
	static int n,m;
	static int[][] ar;
	static ArrayList<String>[] list;
	public static void main(String[] args) throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		n = Integer.parseInt(st.nextToken());
		m = Integer.parseInt(st.nextToken());
		
		list = new ArrayList[n+3];
		
		for (int i = 0; i < n+3; i++) {
			list[i] = new ArrayList<String>();
		}
		// List 1에 해당하는 값을 집어넣음
		list[1].add("1");
		
		// List 2에 해당하는 연산을 집어넣음
		list[2].add("1+1");
		list[2].add("2");
		// List 3에 해당하는 연산을 집어넣음
		list[3].add("1+1+1");
		list[3].add("1+2");
		list[3].add("2+1");
		list[3].add("3");
		
		//1,2,3은 모두 정해졌으므로 그 다음을 보면
		for (int i = 4; i <= n; i++) {
			for (int j = 1; j <= 3; j++) {
				for (String s : list[i-j]) { //i = 4 => j = 1 
//					ArrayList[i-1] 에 있는 수식에 +1을 (ex i == 4, j == 1 => ArrayList[4-1]에 +1)
//					 ArrayList[i-2] 에 있는 수식에 +2을 (ex i == 4, j == 2 => ArrayList[4-2]에 +2)
//					 ArrayList[i-3] 에 있는 수식에 +3을 (ex i == 4, j == 2 => ArrayList[4-3]에 +3)
					list[i].add(j + "+" + s); 
				}
			}
		}
		if(list[n].size() < m) {
			System.out.println(-1);
		}
		else {
			System.out.println(list[n].get(m-1));
		}