1. 程式人生 > >【DP_動態規劃】整數劃分

【DP_動態規劃】整數劃分

題目連結:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=90

整數劃分

時間限制:3000 ms  |  記憶體限制:65535 KB

難度:3

輸入

第一行是測試資料的數目M(1<=M<=10)。以下每行均包含一個整數n(1<=n<=10)。

輸出

輸出每組測試資料有多少種分法。

描述

將正整數n表示成一系列正整數之和:n=n1+n2+…+nk, 
其中n1≥n2≥…≥nk≥1,k≥1。 
正整數n的這種表示稱為正整數n的劃分。求正整數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。 


#include <iostream>

using namespace std;

int cnt,n;
int memo[11][11];

void init();
int dp(int n, int m);

int main()
{
    cin>>cnt;
    while(cnt--)
    {
        cin>>n;
        init();
        cout<<dp(n, n)<<endl;
    }
    return 0;
}

void init()
{
    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<=n; j++)
        {
            memo[i][j]=0;
        }
    }
}
int dp(int n, int m)
{
    if(memo[n][m])
    {
        return memo[n][m];
    }
    else if(n==1||m==1)
    {
        memo[n][m]=1;
        return memo[n][m];
    }
    else if(m>n)
    {
        memo[n][m]=dp(n, n);
        return memo[n][m];
    }
    else if(m==n)
    {
        memo[n][m]=1+dp(n, m-1);
        return memo[n][m];
    }
    else
    {
        memo[n][m]=dp(n-m, m)+dp(n, m-1);
        return memo[n][m];
    }
}

【2018/11/8後記】

1.本題用了動態規劃法+備忘錄法,遞迴公式如下:

其中q(n,m)代表:要劃分的整數為n,最大的加數<=m

如:q(3,2)代表:將3進行劃分,最大的加數不能超過2,因此只有2+1,1+1+1這兩種分法,因此q(3,2)=2

n和m的值有以下幾種情況:

第一種情況:當n==1時,即要劃分的整數為1,自然只有一種分法;當m==1時,n只能被劃分成n個1相加,也只有一種分法

第二種情況:當n<m時,即要劃分的整數為n,加數<=m。又因為加數<=n&&n<m,所以q(n,m)=q(n,n)

第三種情況:當n=m時,我們可以將其分成兩種子情況:

①子情況:讓最大的加數=m,那麼分法只有1種:n=m

②子情況:讓最大的加數<=m-1,那麼問題轉換成q(n,m-1),因為m=n,所以q(n,m-1)=q(n,n-1)

所以,第三種情況的分法q(n,m)=1+q(n,n-1)

第四種情況:當n>m時,我們可以將其分成兩種子情況:

①子情況:讓最大的加數=m,那麼問題轉換成q(n-m,m)

②子情況:讓最大的加數<m,那麼問題轉換成q(n,m-1)

所以,第四種情況的分法q(n,m)=q(n-m,m)+q(n,m-1)

詳細講解請轉這篇部落格:https://blog.csdn.net/qq_41333482/article/details/82823742 

2、這道題跟裝盤子那道差不多了 ,都是要分子情況