--- 整數劃分解報告 ---- By Debugcool
-------------------------------------------------------
1.問題描述:
給定一個正整數N和K
1.> 將n劃分成若干正整數之和的劃分數。
2.> 將n劃分成k個正整數之和的劃分數。
3.> 將n劃分成最大數不超過k的劃分數。
4.> 將n劃分成若干奇正整數之和的劃分數。
5.> 將n劃分成若干不同整數之和的劃分數。
2.問題分類:總的來說這些都是背包問題;
第一個問:就是一個完全背包,背包有 1 --- N 種,第 i 種背包的重量為 i ,價值為 i ;這很好解決:
dp[0] = 1;
for (i = 1;i <= N;i++)
for (j = i;j <= N;j++)
dp[j] += dp[j-i];
其中 dp[j] 是用前 i 個數能構成 j 的種類數,則結果就為 dp[N]
看完這個問題了,那麼 第3個問就知道了 , 即用前 K 種背包來裝 所得結果,只需把第一層迴圈的 i <= N 改為 i <= K 即可;
dp[0] = 1;
for (i = 1;i <= K;i++)
for (j = i;j <= N;j++)
dp[j] += dp[j-i]; 結果同樣為 dp[N] ;
那麼第四個問呢,想想是奇數,那麼 i = 2,4,6,…… 等等值就不能取了,因為這些背包種類不合要求,這很簡單啊 i++ 改為 i += 2 不就行了;
dp[0] = 1;
for (i = 1;i <= N;i+=2)
for (j = i;j <= N;j++)
dp[j] += dp[j-i]; 結果同樣為 dp[N] ;
再看看第五個問,若干個不同的???想到了什麼,就是一種背包最多隻能用一次???這是什麼,經典的 01背包 啊,與第一個問的不同就是第二層迴圈的順序而已;
dp[0] = 1;
for (i = 1;i <= N;i++)
for (j = n;j >= i ;j--)
dp[j] += dp[j-i];
最後我們來思考第二個問:
要求只要 K 個,這怎麼辦呢???想想特殊情況…… 如果 K = 1 呢,只能是 N 咯,若果 N = 0 呢, 結果只能是 0 中可能啊,那同樣N < K 的話,不可能分啊 結果為 0 ,好,特殊的考慮完了,那麼我們再考慮,分的結果中有沒有 1 , 如果有 那麼就把剩下的 N - 1 分成 K - 1 份 , 如果沒有呢,那麼我們先拿出 K 份 給每一堆 一個1, 再把剩下的 N - K 分成 K 份就行了啊,好了,至此,遞迴方法出來了:
int work(int n,int k)
{
if (k == 1)
return 1;
if (n == 0)
return 0;
if (n < k)
return 0;
return work(n-k,k) + work(n-1,k-1);
}
--------------------------------
總結:背包問題是基礎啊~~~
Debugcool---------------