划分型dp-數的划分


題目描述  Description

將整數n分成k份,且每份不能為空,任意兩種划分方案不能相同(不考慮順序)。
例如:n=7,k=3,下面三種划分方案被認為是相同的。
1 1 5

1 5 1

5 1 1
問有多少種不同的分法。

輸入描述  Input Description

輸入:n,k (6<n<=200,2<=k<=6)

輸出描述  Output Description


輸出:一個整數,即不同的分法。

樣例輸入  Sample Input

 7 3

樣例輸出  Sample Output

4

//

解析:這一題實際上是組合數學里面的經典問題,跟第二類Stirling數有些相似。可以把一個數值為n的數看成n個小球,划分的份數k看作是k個盒子,那么本題的要求就是:
將n個小球放到k個盒子中,小球之間與盒子之間沒有區別,並且最后的結果不允許空盒
與第二類Stirling數的遞推公式的推導過程相似:
將n個小球放到k個盒子中的情況總數=1、至少有一個盒子只有一個小球的情況數+2、沒有一個盒子只有一個小球的情況數
 
這樣進行划分的原因是這種分類足夠特殊,1和2都有可以寫出來的表達式:
1. 因為盒子不加區分,那么1的情況數與“將n-1個小球放到k-1個盒子中”的情況數一樣
2. 沒有一個盒子只有一個小球,那么把每個盒子中拿出來一個小球,對應的是“把(n-k)個小球放到k個盒子中的情況數”
至於1和2中的兩種等價關系為什么成立,可以用集合A=集合B的方式去證明
 
最后將上面的敘述轉化為dp的表達形式:
f[n][k]代表將n個小球放到k個盒子中且沒有空盒的情況,那么f[n][k] = f[n-1][k-1] + f[n-k][k]
(copy自大神)

代碼

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int dp[1000][1000];
int main()
{
int i,j,x,n,k;
cin>>n>>k;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
{
if(i==j) dp[i][j]=1;
else dp[i][j]=dp[i-j][j]+dp[i-1][j-1];
}
cout<<dp[n][k]<<endl;
return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM