백준/동적계획법

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

2zreal 2024. 7. 17. 17:10

문제 해결 방법

1. 1부터 N까지 연산의 최솟값을 구한다.(DP배열)

2.  N을 1로 만드는 방법을 위 값을 기반으로 찾는다.

 

2의 연산의 최솟값은 1이다.

2에서는 2-1, 2/2만 가능하다 2/3은 불가능

 

3의 연산의 최솟값은 1이다.

3에서는 3-1, 3/3이 가능한데 이 중 최솟값을 골라서 저장하면 되는 것이다. DP[1]<DP[2]이기 때문에 DP[1]을 선택하고

DP[1]+1값을 저장한다.

DP[3]=DP[1]+1

 

위 과정을 반복하면 

DP배열은 이런 식으로 저장된다.

 

N에서 1로 만드는 방법은 위 배열을 이용해서 거꾸로 가면 된다.

10에서 보면 DP[10/3]은 불가능 DP[10/2]는 3의 연산 횟수 DP[10-1]은 2의 연산 횟수 결국 가장 작은 DP[9]가 선택된다. 이런 식으로 DP[1]까지 반복하면 된다.

 

 

#include <iostream>

using namespace std;

int DP[1000001];

int main(void)
{
	int N=0;
	
	cin>>N;
	
	for(int i=2; i<=N; i++)
	{
		int max=987654321;
	
		if(DP[i/3]+1<max&&i%3==0)
		{
			max=DP[i/3]+1;
		}
		if(DP[i/2]+1<max&&i%2==0)
		{
			max=DP[i/2]+1;
		}
		if(DP[i-1]+1<max)
		{
			max=DP[i-1]+1;
		}
		DP[i]=max;
	}
	
	for(int i=1; i<=N; i++)
	{
		cout<<DP[i]<<" ";
	}
	
	cout<<endl;
	
	int i=N;
	
	while(true)
	{
		cout<<i<<" ";
		if(i==1)
		{
			break;
		}
		
		int max=987654321;
		int next=0;
		
		if(DP[i/3]<max&&i%3==0)
		{
			max=DP[i/3];
			next=i/3;
		}
		if(DP[i/2]<max&&i%2==0)
		{
			max=DP[i/2];
			next=i/2;
		}
		if(DP[i-1]<max)
		{
			max=DP[i-1];
			next=i-1;
		}
		
		i=next;
		
	}
	
	return 0;
}