(C語言)整數劃分問題 遞迴和遞推
阿新 • • 發佈:2019-01-02
對於一個正整數n的劃分,就是把n變成一系列正整數之和的表示式。注意,分劃與順序無關,例如6=5+1跟6=1+5是 同一種分劃。另外,單獨這個整數本身也算一種分劃。 例如:對於正整數n=5,可以劃分為: 1+1+1+1+1 1+1+1+2 1+1+3 1+2+2 2+3 1+4 5輸入描述
輸入一個正整數n
輸出描述
輸出n整數劃分的總數k
輸入樣例
5
輸出樣例
7
1、問題描述和分析
對於一個正整數n的分化,就是把n表示成一系列正整數之和的表示式。注意,分劃與順序無關,例如6=1+5 和 6=5+1被認為是同一個劃分。另外,這個整數n本身也算是一種分化。
分析:
所謂整數劃分,是指把一個正整數n寫成如下形式: n=m1+m2+...+mi; (其中mi為正整數,並且1 <= mi <= n),則{m1,m2,...,mi}為n的一個劃分。
如果{m1,m2,...,mi}中的最大值不超過m,即max(m1,m2,...,mi)<=m,則稱它屬於n的一個m劃分。這裡我們記n的m劃分的個數為f(n,m);
例如但n=4時,他有5個劃分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};
2、資料結構和演算法
該問題是求出n的所有劃分個數,即f(n, n)。下面我們考慮求f(n,m)的方法,採用遞迴法, 根據n和m的關係,考慮以下幾種情況:
(1)當n=1時,不論m的值為多少(m>0),只有一種劃分即{1};
(2)當m=1時,不論n的值為多少,只有一種劃分即n個1,{1,1,1,...,1};
(3)當n=m時,根據劃分中是否包含n,可以分為兩種情況:
(a)劃分中包含n的情況,只有一個即{n};
(b)劃分中不包含n的情況,這時劃分中最大的數字也一定比n小,即n的所有(n-1)劃分。
因此 f(n,n) =1 + f(n,n-1);
(4)當n<m時,由於劃分中不可能出現負數,因此就相當於f(n,n);
(5)但n>m時,根據劃分中是否包含最大值m,可以分為兩種情況:
(a)劃分中包含m的情況,即{m, {x1,x2,...xi}}, 其中{x1,x2,... xi} 的和為n-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);
綜上所述:
f(n, m)= 1; (n=1 or m=1)
f(n,m) = f(n, n); (n<m)
1+ f(n, m-1); (n=m)
f(n-m,m)+f(n,m-1); (n>m)
遞迴程式碼:
#include<iostream>
using namespace std;
int Divinteger(int n,int m) {
if(n == 1||m == 1)
return 1;
else if(n < m)
return Divintege(n,n);
else if(n == m)
return 1+Divintege(n,n-1);
else
return Divintege(n,m-1) + Divintege(n-m,m);
}
int main(void) {
int n;
while(scanf("%d",&n) != EOF && (n >= 1)) {
printf("%d\n",Divintege(n,n));
}
return 0;
}
遞推公式:
遞推就是打表,通過矩陣存下所有的個數,公式和思路與上面的一致,只需要把下面程式碼中的 i 看成 n ,j 看成 m,然後初始化 i = 0時候所有的值,
遞推程式碼:
#include<stdio.h>
int resolve(int a,int max)
{
if(a == 1||max ==1)
return 1;
if(a == max)
return resolve(a,max-1)+1;
if(a > max)
return resolve(a,max-1)+resolve(a-max,max);
if(a < max)
return resolve(a,a);
else return 0;
}
int main()
{
int n;
int sum;
scanf("%d",&n);
sum = resolve(n,n);
printf("%d",sum);
return 0;
}