整數劃分問題:
將正整數n表示成一系列正整數之和:n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1,k≥1。正整數n的這種表示稱爲正整數n的劃分。求正整數n的不同劃分個數。
算法分析:
根據n和m的關係,可以考慮下面幾種情況:
(1)當n = 1時,不管m的值爲多少(m > 0),只有一種劃分即 { 1 }。
(2)當m = 1 時,不管n的值爲多少,只有一種劃分即n個1,{1,1,1,1…..1}。
(3)當n = m 時,根據劃分中是否包含n,可以劃分兩種情況:
(a)劃分中包含n的情況,只有一個,即{ n }。
(b)劃分中不包含n的情況,這時候劃分中最大的數字也一定比n小,及n的所有n-1劃分,因此可以用遞歸來解決f(n,n) = f(n,n-1)+1.
(4)當n < m 時,由於劃分中不可能出現負數,(n最多也就是n個1,因此不可能出現m個劃分相加,不可能出現負數)因此相當於f(n,n) 。
(5)當n > m 時,根據劃分中是否包含最大值m,可劃分爲兩種情況:
(a)劃分中包含m的情況,即{m, {x1,x2,…xi}}其中{x1,x2,….xi}的和位n – m,可能再次出現m, 因此是(n - m)的m劃分,因此這種劃分個數爲f(n – m,m)
(b)劃分中不包含m的情況,則劃分中所有值都比m小,即n的(m - 1)劃分,個數爲f(n, m-1),因此f(n,m) = f(n – m, m) + f(n,m - 1).
綜合以上情況,可以看出,整數劃分具有遞歸定義的特徵,其遞歸表達式爲:
算法實現
// test01_huafen.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
int q(int n,int m)
{
if ((n<1)||(m<1)) return 0;
if ((n==1)||(m==1)) return 1;
if (n<m) return q(n,n);
if (n==m) return q(n,m-1)+1;
return q(n,m-1)+q(n-m,m);
}
int _tmain(int argc, _TCHAR* argv[])
{
int n;
printf("輸入一個整數:");
scanf("%d",&n);
printf("%d",q(n,n));
scanf("%d",n);
return 0;
}
結果:
輸入一個整數: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;
如上圖劃分所示,總共有11中不同的劃分結果。