1. 程式人生 > >整數劃分問題(遞迴&遞推)

整數劃分問題(遞迴&遞推)

1:問題描述:

整數劃分問題是將正整數n表示成一系列正整數之和:n=n1+n2+n3+...+nk,其中n1>=n2>=n3>=...nk>=1,這種表示方法稱為整數劃分。求正整數n的不同劃分個數。

例如:6的整數劃分如下(共11種)

6

5+1

4+2;4+1+1;

3+3;3+2+1;3+1+1+1;

2+2+2;2+2+1+1;2+1+1+1+1+1;

1+1+1+1+1+1

問題分析:

為正整數n劃分數,為了容易找到遞迴關係,考慮增加一個自變數,其中n為給定的正整數,m為劃分中的最大加數,劃分個數記為f(n,m)這樣就可以找出如下遞迴關係:

一:最大加數m<=1的時候,這時候任何正整數都只有一種劃分方法,即:n=1+1+1+...1;

二:最大加數m>n的時候(實際上m不能大於n)這個時候 f(n,m)=f(n,n);

三:最大加數m=n的時候,這時,分為兩種情況:

1:包括n,這時正整數與最大加數一樣,劃分方法只有一種,{n};

2:若不包括n ,這個時候最大加數為n-1,所以劃分方法為 :f(n,n-1);

所以,當m=n時,f(n,m)=f(n,n-1)+1;

四:最大加數m<n,這個時候同樣分為兩種情況:

1:包括m ,這個時候最大加數就是m,劃分方法為:f(n-m,m);

2:不包括m ,這個時候最大加數就是m-1,劃分方法為:f(n,m-1);

所以,當m<n時,f(n,m)=f(n,m-1)+f(n-m,m)

編碼如下

遞迴:

#include<iostream>
using namespace std;
int f(int n, int m)
{
    if(m<1||n<1) {
        return 0;
    }
    else if (m>n){
        return f(n,n);
    }
    else if(m==n){
        return (f(n,m-1)+1);
    }
    else{
        return (f(n-m,m)+f(n,m-1));
    }
}


int main()
{
     int n;
     cin>>n;
     cout<<f(n,n)<<endl;
    return 0;
}

遞推:

#include<iostream>
using namespace std;
int main()
{
    int i,j,m,n;
    int f[100][100];
    cin>>n>>m;
    for(i=1;i<=m;i++){
        f[0][i]=1;
    }
    for(i=1;i<=n;i++){
        f[i][0]=0;
    }
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            if(i<j){
                f[i][j]=f[i][i];
            }else if(i==j){
                f[i][j]=(f[i][j-1]+1);
            }
            else{
                f[i][j]=(f[i][j-1]+f[i-j][j]);
            }
        }
    }
    cout<<f[n][m]<<endl;
}