Luogu P1025 数的划分(递推 DP DFS)

 P1025 数的划分

题目描述

将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

例如:n=7,k=3,下面三种分法被认为是相同的。

1,1,5; 1,5,1; 5,1,1;

问有多少种不同的分法。

输入输出格式

输入格式:

n,k (6<n<=200,2<=k<=6)

输出格式:

一个整数,即不同的分法。

输入输出样例

输入样例#1:
7 3
输出样例#1:
4

说明

四种分法为:1,1,5;1,2,4;1,3,3;2,2,3;

noip2001年提高组第二题

  这道题对于我来说是一道有难度的题((´-_-)-_-)-_-)

  有三种思路,递推,DP,爆搜(dfs骗分神器)!

  AC①:dfs (24ms)

  

 1 #include <cstdio>
 2 
 3 int ans, n, k;
 4 
 5 // left表示还有多大数字没分
 6 // num表示还需分成几份
 7 // last表示上次分的数字是多少
 8 void dfs(int left, int num, int last)
 9 {    //条件
10     if(num == 1)
11     {
12         ans++;
13         return;
14     }
15     else
16     {    //为什么是i = last  因为要避免分的重复 这样就能从小到大以次分(剪枝)
17         //为什么i<=left/num 因为要保证后面的几份也能分到一个数
18         for(int i=last; i<= left/num; i++)
19             dfs(left-i, num-1, i);
20     }
21 }
22 
23 int main()
24 {
25     scanf("%d%d", &n, &k);
26     //把n分成k份 从1开始分
27     dfs(n, k, 1);
28     printf("%d", ans);
29     return 0;
30 }

  第二种方法是递推

  这里要感谢DoubleCakes大大的 http://blog.csdn.net/u013174702/article/details/45620723

  把n看成是n个小球,k看成是k个盒子

  那么题目就变成了把n小球放到k个盒子,且每个盒子都至少有1个小球的问题。

  那么把n个小球放到k个盒子里的情况总数 = 1.至少有1个盒子放1个小球的情况总数 + 2.每个盒子都有多于1个小球的情况总数

  那么这里 1 相当于 把n-1个小球放到k-1个盒子里的情况总数

  2 相当于 把n-k个小球放到k个盒子里的情况总数

  到了这里就可以发现是递推咯。

  公式为 f(n,k) = f(n-1,k-1) + f(n-k,k)

  你说n<k时候? 请看代码

  AC②: 递推 (32ms)

 1 #include <cstdio>
 2 
 3 int ss(int n, int k)
 4 {
 5     if(n < k) return 0;    //如果n<k 肯定不可能每个盒子都有
 6     if(n == k) return 1;//盒子和小球数相等 只有一种方案 每个盒子里一个小球
 7     if(k == 1) return 1;//盒子只有一个时候 把剩下小球都放进去
 8     return ss(n-1, k-1) + ss(n-k, k);
 9 }
10 
11 int main()
12 {
13     int n, k;
14     scanf("%d%d", &n, &k);
15     printf("%d", ss(n, k));
16     return 0;
17 }

  第三种方法是DP

  其实理解了递推,那么就能理解dp了。

  方程为f[i][j] = f[i-1][j-1] + f[i-j][j]

  边界 f[0][0] = 1

  那么还有不懂就看代码吧

  AC⑨: dp(0ms dp大法好)

 1 #include <cstdio>
 2 
 3 int f[205][10];
 4 //f[n][k]表示将n分成k份的方案总数
 5 int main()
 6 {
 7     int n, k;
 8     scanf("%d%d", &n, &k);
 9     f[0][0] = 1;
10     for(int i=1; i<=n; i++)
11     {
12         // j<=i保证i-j>=0   要记得还有 j<=k
13         for(int j=1; j<=i && j<=k; j++)
14         {
15             f[i][j] = f[i-1][j-1] + f[i-j][j];
16         }
17     }
18     printf("%d", f[n][k]);
19     return 0;
20 }
原文地址:https://www.cnblogs.com/yBaka/p/7391293.html