分糖果_100分_B卷_分治递归/动态规划

文章讲述了如何使用递归和动态规划方法解决分发糖果的问题,小明最少需要将任意数量的糖果分至只剩一颗,通过计算糖果数量为奇数和偶数时的分配策略,找到所需的最少次数。
摘要由CSDN通过智能技术生成

分班问题

题目描述:

小明从糖果盒中随意抓一把糖果,每次小明会取出一半的糖果分给同学们。
当糖果不能平均分配时,小明可以选择从糖果盒中(假设盒中糖果足够)取出一个糖果或放回一个糖果。
小明最少需要多少次(取出、放回和平均分配均记一次),能将手中糖果分至只剩一颗。

输入输出描述:

输入描述:

  抓取的糖果数(<10000000000)

输出描述:

  最少分至一颗糖果的次数:

示例1:

输入:
	15
输出:
	5
解释:
	(1)15+1=16;
	(2)16/2=8;
	(3)8/2=4;
	(4)4/2=2;
	(5)2/2=1;

解题思路:

解题思路1:递归求解

定义递归:
①递归基:如果待分配的糖果数量 n 为 1,则分配次数为 0
②根据糖果 n 的性分配:
  若糖果数量 n 是偶数,则分配次数为:本次折半分 + 折半后还需要多少次糖果数量才是1,即:1 + 递归(n/2)
  若糖果数量 n 是奇数,则分配方式有两种,一是放入一颗糖、二是拿出一颗糖,是糖果的数量为偶数在均分,要是最终的分配数量最少,则就选这两种分配方式最少的那个方案。故有:次数为:本次糖果加/减1 + 调整糖果为偶数后均分(次数1) + 均分后继续分,即:1 + 1 + min{递归((n+1)/2), 递归((n-1)/2)}

代码1:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	int n = scanner.nextInt();
	// 开始递归,糖果数量从 [1, 0]
	int dfs = dfs(n, 0);
	System.out.println(dfs);
}

private static int  dfs(int n, int count) {
	// 让过数量为 0 时,分配次数不再增加
	if (n == 1) {
		return count;
	}

	if (n % 2 == 0) {
		return dfs(n / 2, count + 1);
	} else {
		// 奇数,要先变成偶数(次数+1),然后偶数折半(+1),折半后继续分直到为1
		return Math.min(dfs((n + 1) / 2, count + 2), dfs((n - 1) / 2, count + 2));
	}
}

解题思路2:动态规划——也可以理解为递归的至底向上的迭代版本

根据上面递归版本和题目意思,能够得到下面的动态规划方程:
d p [ i ] = { 0 i = 0 ∣ ∣ i = 1 min ⁡ { d p [ ( i − 1 ) / 2 ] , d p [ ( i + 1 ) / 2 ] } + 2 2 ≤ i dp[i] = \begin{cases} 0 & i = 0 \quad||\quad i = 1 \\ \min\{ dp[(i - 1) / 2], \quad dp[(i + 1) / 2]\} + 2 & 2 \leq i \end{cases} dp[i]={0min{dp[(i1)/2],dp[(i+1)/2]}+2i=0∣∣i=12i

代码2:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	int n = scanner.nextInt();
	
	// 初始化,当糖果数量为0、1时,分配次数都是0
	int[] dp = new int[n + 1];
	dp[0] = 0;
	dp[1] = 0;

	for (int i = 2; i <= n; i++) {
		if (i % 2 == 0) {
			// 如果是偶数,则等于分一半的次数 + 1次
			dp[i] = dp[i / 2] + 1;
		} else {
			// 如果是奇数,则等于分一半的次数 + 2次(一次是将糖果变偶数、一次是将偶数个糖果变成折半分)
			dp[i] = Math.min(dp[(i - 1) / 2], dp[(i + 1) / 2]) + 2;
		}
	}
	// n 个糖果分完所需的次数
	System.out.println(dp[n]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值