问题描述
将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5; 1,5,1; 5,1,1;
问有多少种不同的分法。
输入格式
n,k
输出格式
一个整数,即不同的分法
样例输入
7 3
样例输出
4 {四种分法为:1,1,5;1,2,4;1,3,3;2,2,3;}
注意一下:输出后面的{}就是一个注释而已,实际只需要输出4就可了
这道题虽然看着简单,找到状态方程我也是参考了不少解答才想明白,害,算法还是得多练,否则脑袋转不过来。
首先我们要建立存放结果的数组,dp[n][k],对数字n的k种划分情况
这道题是个不重复问题的关键点在于怎么处理1,我们需要对划分结果存在1与不存在1的情况进行分别思考。举个例子(这个例子想不明白的可以把这题想象成把n个球装进k个不同的盒子之类的问题)。
①、现在我进行3的两种划分,那么划分结果就是{1,2},假如我在后面加一个1,变成了{1,2,1},那么它就变成了4的3种划分。由此展开,抽象成代码(eg:4的3种划分),那么此种情况下就有
dp[n][k]=dp[n-1][k-1]
②、(复读一遍)现在我进行3的两种划分,那么划分结果就是{1,2},如果我们将3的两种划分这种情况的每个划分结果+1,那么{1,2}就变成了{2,3},即5的 两种划分。这种情况意味着什么:即对于划分结果(eg:5的两种划分)中每一种结果大于2的,我们将它的每个值-1也不会影响到最终的划分 结果数。那么由此展开,抽象成代码。
dp[n][k]=dp[n-k][k]
于此同时,参考①,就5的划分而言,它还存在{4}+{1}此种划分。
根据①和②我们可以得到状态转移方程
dp[n][k]=dp[n-k][k]+dp[n-1][k-1]
完整代码如下
import java.util.*;
public class 数的划分 {
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int k=sc.nextInt();
int[][] dp=new int[n+1][k+1];//把数字n划分为k个数
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++){
if(j>i)
continue;
if(j==i || j==1)
dp[i][j]=1;
else if
/*两种情况
1.将前一个数字的j划分的最后一个值添加一个1,即为当前数字的j+1划分的方案
2.如果不是1则说明前数字的划分中每个数字至少为2,那么我们把当前数字i-j
*/
dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
}
System.out.println(dp[n][k]);
}
}
本文详细解析了一道关于数的划分算法题目,通过建立dp数组并利用状态转移方程dp[n][k]=dp[n-k][k]+dp[n-1][k-1],解决了将整数n分成k份的不同分法问题。
440

被折叠的 条评论
为什么被折叠?



