본문 바로가기

Programming/Algorithms

백준 #2193. 이친수 / C++ / Dynamic Programming

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

 

2193번: 이친수

0과 1로만 이루어진 수를 이진수라 한다. 이러한 이진수 중 특별한 성질을 갖는 것들이 있는데, 이들을 이친수(pinary number)라 한다. 이친수는 다음의 성질을 만족한다. 이친수는 0으로 시작하지 않는다. 이친수에서는 1이 두 번 연속으로 나타나지 않는다. 즉, 11을 부분 문자열로 갖지 않는다. 예를 들면 1, 10, 100, 101, 1000, 1001 등이 이친수가 된다. 하지만 0010101이나 101101은 각각 1, 2번 규칙에 위배되

www.acmicpc.net

문제에서 제시한 이친수의 조건

1. 0으로 시작하지 않는다.

2. 1이 두 번 연속해서 나타나지 않는다.

 

N이 1일 경우부터 차례차례 생각해보면 금방 해답을 구할 수 있다.

 

N = 1일 때 이친수는 1                              (0 은 불가능)

N = 2일 때 이친수는 10                            (11은 불가능)

N = 3일 때 이친수는 100, 101

N = 4일 때 이친수는 1000, 1001, 1010

 

즉,

 

N = 1일 때 이친수는 1 

N = 2일 때 이친수는 10

 

N = 2일 때 이친수는 10

N = 3일 때 이친수는 100, 101

 

N = 3일 때 이친수는 100, 101

N = 4일 때 이친수는 1000, 1001, 1010

 

 

다음으로 알 수 있는 것은

1. N-1자리 이친수에서 뒤에 1이나 0을 붙여 N자리 이친수를 나타낼 수 있다.

2. 1은 두 개 이상 연속할 수 없으니 N-1자리 이친수가 1로 끝난다면 N자리 이친수가 되려면 0밖에 붙을 수 없다.

3. 0으로 끝나는 N-1자리 이친수는 뒤에 0과 1을 붙여 N자리 이친수를 만들 수 있다.

 

따라서, N마다 끝자리 수가 0일 경우와 1일 경우를 세면 된다.

 

count[91][2] 배열의 행은 N, 열 2개 중 첫 번째 열은 끝자리 수가 0일 때, 두 번째 열은 끝자리 수가 1일 경우를 센다.

ex. count[5][0] : N = 5일 때 끝자리 수가 0인 수의 개수

 

이 식들을 토대로 다음과 같은 점화식을 도출할 수 있다.

더보기

count[i][0] = count[i-1][0] + count[i-1][1];

count[i][1] = count[i-1][0];

 

다음은 소스코드이다.

#include <iostream>
using namespace std;

int main() {

	int n;
	long long count[91][2] = { {0, 0}, {0, 1}, {1, 0} }; //0 count, 1 count

	cin >> n;

	for (int i = 2; i <= n; i++) { //dynamic programming
		count[i][0] = count[i - 1][0] + count[i - 1][1];
		count[i][1] = count[i - 1][0];
	}

	cout << count[n][0] + count[n][1];

	return 0;
}