728x90
개요
문제 링크
실버 1, Greedy
n을 최소 개수의 피보나치 수의 합으로 나타내기
접근
- 우선 쟁점은 모든 n이 피보나치 수의 합으로 만들어질 수 있는가? 이다. 문제에서는 맞다고 하고 넘어갔는데 이해가 안됐다.
- {서로 다른 피보나치 수의 합의 집합} = 자연수 임을 확인한다.
귀납법이랑 이런저런 방법을 해보다가 막혀서 질문 게시판에 올라온 제켄도르프의 정리에 대해 읽어봤다. 역시 이런 걸 보면 구해보고 싶은 마음은 다들 비슷한가보다. 방법은 결국 귀납법이었다.
1) n = 1 일때는 반드시 된다.
n = 1 -> {1}
2) n = k 까지가 모두 된다고 가정하고 n = k+1에 대해 가능한지 확인하자.
n = k -> set(k)
n = k+1 = 피보나치수 -> {fib(i)}
n = k+1 != 피보나치수 -> {fib(i), set(n-fib(i))}
// fib(i) = n보다 작은 최대 피보나치수
n-fib(i) < k 임이 자명하므로 1~k까지 구성이 가능하다면 k+1도 구성이 가능하다. 이 내용은 chatGPT에 물어봐도 잘 알려준다.
- 문제로 돌아와서, 모든 자연수가 피보나치 구성이 가능하므로 n-fib(i) 연산을 지속해주면 된다.
Pseudo code
while(n)
fib = n보다작은최대피보나치수
n -= fib
출력목록.append(fib)
Source code
#include <bits/stdc++.h>
using namespace std;
const int N = 45;
vector <int> fib;
void test() {
int n;
cin >> n;
vector <int> q;
for (int i=N; i>=1; i--)
if (fib[i] <= n) {
q.push_back(fib[i]);
n -= fib[i];
}
if (n)
cout << n << " ";
n = q.size();
for (int i=0; i<n; i++)
cout << q[n-1-i] << " ";
cout << "\n";
}
int main() {
fib.push_back(0);
fib.push_back(1);
for (int i=2; i<=N; i++)
fib.push_back(fib[i-1]+fib[i-2]);
int t;
cin >> t;
while(t--) test();
}
728x90
'백준브실골 > Greedy' 카테고리의 다른 글
백준 1339, 단어 수학 (0) | 2023.02.11 |
---|---|
백준 12237, Up and Down (Large) (0) | 2023.02.09 |
백준 13884, 삭삽 정렬 (0) | 2023.02.08 |
백준 4889, 안정적인 문자열 (0) | 2023.02.08 |
백준 25683, 행렬 곱셈 순서 4 (0) | 2023.02.08 |
백준 14926, Not Equal (0) | 2023.02.08 |
백준 23758, 중앙값 제거 (0) | 2023.02.08 |
백준 1105, 팔 (0) | 2023.02.08 |
댓글