蓝桥杯 算法训练 数的划分——动态规划

本文详细解析了一道关于数的划分算法题目,通过建立dp数组并利用状态转移方程dp[n][k]=dp[n-k][k]+dp[n-1][k-1],解决了将整数n分成k份的不同分法问题。

问题描述
  将整数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]);
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Demonslzh6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值