1. 程式人生 > >整數劃分問題【遞迴以及遞推求解方式】

整數劃分問題【遞迴以及遞推求解方式】

簡述

先寫遞迴,有了遞迴之後,就換用遞推來加快速度。

演算法思路

  • 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); }