問題
劃分數就是將整數 n 分成若干個大於 0 的數的和。例如,n = 4,可以分成 1+1+1+1,1+1+2,1+3,2+2,4,一共 5 種方案,注意 1+1+2,1+2+1,2+1+1被認爲是相同的方案。
求整數 80 的劃分數方案。
答案
15796476
思路
還是用dfs做,只是有點慢(要25s)( ̄▽ ̄)”(只適合小數,如果是大數的話就很慢了)。
也可以用遞歸做,將遞歸函數的聲明爲 int d(int n, int m);其中n爲要劃分的正整數,m是劃分中的最大加數(當m > n時,最大加數爲n),分下列幾種情況:
- 當 n=1,d爲1,因爲無論m爲多少就只有1
- 當 m=1 時,d=1 ,由上例可知,當 n=4 時,d只有 1+1+1+1 這1種
當 n=m 時,又分爲兩種情況:
- 第一種就是包含m的時候,就只有 m 這一種。
- 另外一種就是不包含 m ,那麼最大數就爲 m-1 ,有 d(n,m-1) 種
因此當 n=m 時,d(n , n)=1+ d(n,n-1)
當n < m 就相當於 d(n,n) 了
當 n > m 時,一種是不含m,爲d(n,m-1)種,一種是含有m,有d(n-m,m)種
因此d(n,m)=d(n-m,m)+d(n,m-1)
注意理解d(n-m,m),注意這裏的前提是劃分包含m,所以將m提出來一個,保證劃分中一定會有m,剩下數字劃分的和爲n-m,而這n-m中可能不會出現m,也可能出現m,但由於我們已經提出了一個m,所以此處不用擔心m是否再出現。第一個數爲什麼是(n-m),原因是提出一個m後,已經保證了劃分中一定出現m,而n-m還沒有進行劃分,這裏忽略提出的m,對剩下的整數n-m進行劃分,劃分的最大值仍然是m
代碼
- dfs代碼
#include <iostream>
using namespace std;
int total=0;
void dfs(int a,int sum){
if (sum==80) {
total++;
return;
}
if (sum>80) {
return;
}
for (int i=a;i<=80;i++) {
dfs(i,sum+i);
}
}
int main(int argc, char *argv[]) {
dfs(1,0);
printf("%d",total);
return 0;
}
- 遞歸代碼
#include <stdio.h>
int d(int n, int m){
if(n < 1 || m < 1) return 0;
if(n == 1 || m == 1) return 1;
if(n < m) return d(n, n);
if(n == m) return (d(n, m - 1) + 1);
if(n > m) return d(n, m - 1)+d((n - m), m);
}
int main(){
printf("%d",d(80,80));
return 0;
}