整數劃分問題【遞迴以及遞推求解方式】
阿新 • • 發佈:2018-12-10
簡述
先寫遞迴,有了遞迴之後,就換用遞推來加快速度。
演算法思路
q(n, m)
表示,n這個整數被劃分,其中最大可能整數是m的所有劃分情況數目。明顯,所求,即為q(n,n)
- 當
m>n
時,明顯有q(n, m) = q(n, n)
。因為,保證了所有整數都必須是大於等於1的。所以,限制再高的上限都沒有任何的意義。 - 當
m=n
時候,明顯有兩種劃分,第一種就是全部拿走,另一種就是不全部拿走。即,q(n,n) = 1+q(n, n-1)
。 - 當
m<n
時候,同之前的方法類似。要麼是不拿走當前最大值的可能,要麼就是拿走最大值的。即,q(n, m) = q(n, m-1) + q(n-m, m)
為什麼需要考慮後面的兩種分開,主要是為了避免n==0 (n-m == 0)
的時候需要求解。
程式碼
遞迴:
#include <iostream>
using namespace std;
int cal(int n, int m){
if (n==1||m==1) return 1;
if (m > n) return cal(n, n);
if (n==m) return 1 + cal(n, m-1);
return cal(n-m, m) + cal(n, m-1);
}
int main(){
int n;
while(cin >> n && n >= 1)
cout << cal(n, n)<< endl;
}
遞推:
#include <iostream>
using namespace std;
unsigned int** arr;
void cal(int n){
arr = new unsigned*[n+1];
for (int i = 0; i <= n; ++i) arr[i] = new unsigned[n+1];
for (int i = 1 ; i <= n; ++i) arr[i][1] = 1; // max number equal to 1
// arr[i][j] 表示i這個數被劃分時,最大可能的數為j的所有可能。
for (int i = 1; i <= n; ++i)
for (int j = 2; j <= n; ++j)
if (i < j) arr[i][j] = arr[i][i];
else if (i == j) arr[i][j] = 1 + arr[i][j-1];
else arr[i][j] = arr[i][j-1] + arr[i-j][j];
cout << arr[n][n]<< endl;
for (int i = 0; i <= n; ++i) delete []arr[i];
delete [] arr;
}
int main(){
int n;
while(cin >> n && n >= 1)
cal(n);
}