问题
划分数就是将整数 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;
}