[C++] 백준(BOJ) - 12852 : 1로 만들기 2

인프런에 있는 큰돌님의 강의 10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트를 듣고 정리한 필기입니다.

문제

BOJ - 12852 : 1로 만들기 2(링크)

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.

  • X가 3으로 나누어 떨어지면, 3으로 나눈다.
  • X가 2로 나누어 떨어지면, 2로 나눈다.
  • 1을 뺀다.

정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.

입력

첫째 줄에 1보다 크거나 같고, $10^6$보다 작거나 같은 자연수 N이 주어진다.

출력

첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.

둘째 줄에는 N을 1로 만드는 방법에 포함되어 있는 수를 공백으로 구분해서 순서대로 출력한다. 정답이 여러 가지인 경우에는 아무거나 출력한다.

알고리즘

  1. DP

풀이

  • 부분최적구조를 통해 최적해를 찾는 문제
  • Bottom Up 방법으로 DP

코드

// BOJ - 12852 : 1로 만들기 2
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 2147000000;
int n, dp[1000004];

void go(int here)
{
	if (here == 0) return;
	cout << here << ' ';
	if ((here % 3 == 0) && dp[here] == dp[here / 3] + 1) go(here / 3);
	else if ((here % 2 == 0) && dp[here] == dp[here / 2] + 1) go(here / 2);
	else if ((here - 1 >= 0) && dp[here] == dp[here - 1] + 1) go(here - 1);
	return;
}

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);

	cin >> n;
	fill(dp, dp + 1000004, INF);

	// Bottom Up 방법 DP
	dp[1] = 0;
	for (int i = 1; i <= n; i++)
	{
		if (!(i % 3)) dp[i] = min(dp[i], dp[i / 3] + 1);
		if (!(i % 2)) dp[i] = min(dp[i], dp[i / 2] + 1);
		dp[i] = min(dp[i], dp[i - 1] + 1);
	}
	cout << dp[n] << '\n';
	go(n);

	return 0;
}

평가

  • dp 배열을 미리 만들고 반복문 1회를 통해 최적해를 미리 찾기
  • 재귀함수를 이용해 Trace 함수 구현

© 2023 Jinsoo Lee. All rights reserved.

Powered by Hydejack v9.1.6