文章目录
- 题目描述
- 解题思路:
- 思路讲解:
题目描述
有m个苹果,n个小孩。每个小孩都有一个编号,小明的编号是。要尽量公平的分苹果,相邻编号的小孩分到的苹果数目差距不能大于1。
请问如何在满足相邻编号的小孩分到的苹果数目差距不能大于1的情况下,小明分配到的苹果数目最多,并且输出这个最大值,每个小朋友至少需分配到一个苹果。
输入描述
第一行输入三个整数。
输出描述
输出一行,表示小明分配到苹果个数的最大值。
示例 1
4 6 2
输出
2
说明
可以这样分配1 2 2 1。可以小明分配到了2个苹果。
图片:
解题思路:
首先我这边有两种思路,第一种是暴力时间复杂度是O(m),即苹果越多,时间越长,空间复杂度是O(n),因为根据小孩数量声明的切片,具体的地址在https://blog.csdn.net/m0_64941684/article/details/139796892?spm=1001.2014.3001.5501,第二种是利用高中数学中通过计算公式得出范围,不同范围内的苹果数是多少,因为全部是计算,不需要for循环所以时间复杂段和空间复杂度都是O(1),
代码如下
package mainimport ("fmt""math""os"
)// maxApplesForXiaoming 使用贪心策略计算小明最多能分到的苹果数
func maxApplesForXiaoming(m, n, k int) int {// 初始化小明最多能分到的苹果数为1maxApples := 1// 如果只有一个小孩,直接返回所有苹果if n == 1 {return m}if m < n {return -1}m = m - nvar big intvar small intif (k - 1) > (n - k) {big = k - 1small = n - k} else {big = n - ksmall = k - 1}// 确定小明的位置相对于序列长度的位置// 计算从左到小明处能分配的苹果数(等差数列求和)bigSum := (big * (big + 1)) / 2smallSum := (small * (small + 1)) / 2totalEquidifference := bigSum + smallSum + small*(big-small) + big + 1smallEquidifference := smallSum*2 + small + 1switch true {case m > totalEquidifference:maxApples = big + 1 + (m-totalEquidifference)/n + 1return maxApplescase m == totalEquidifference:maxApples = big + 1 + 1return maxApplescase m < totalEquidifference && m > smallEquidifference:maxApples = small + int(math.Sqrt(float64(2*(m-smallEquidifference)+((3+2*small)/2)*(3+2*small)))) - (3+2*small)/2 + 1return maxApplescase m == smallEquidifference:maxApples = small + 1case m < smallEquidifference:maxApples = int(math.Sqrt(float64(m))) - 1return maxApples + 1 + 1}return maxApples
}func main() {var n, m, k int_, err := fmt.Scanln(&n, &m, &k)if err != nil {fmt.Println("Error reading input:", err)os.Exit(1)}result := maxApplesForXiaoming(m, n, k)if result != -1 {fmt.Printf("小明最多能分到的苹果数为: %d\n", result)} else {fmt.Println("无法满足每个小孩至少分到一个苹果的条件")}
}
思路讲解:
通过n,m,k(小孩数量,苹果数量,和编号)进行计算在不同情况下计算方式不同,
首先我们假设编号处于中间,两边可以为0(即k为1或者n),不影响计算,
然后我们定义一些值:
- big 两边大的一边的长度,左边大为左边,右边大为右边
- small 两边小的一边的长度,左边小为左边,右边小为右边
3.bigSum 大的等差总和,即大的那一边从边界到k编号的等差综合,因为边长为big,所以bigSun = (big * (big + 1)) / 2 - smallSun大的等差总和,即小的那一边从边界到k编号的等差综合,因为边长为small,所以smallSun = (small* (small + 1)) / 2
了解这些值之后我们就可以确定一些边界啦
-
边界1:左右两边都是等差,因为相邻孩子苹果数相差不超过1,所以小边等差末尾一般不为1(除非大小边相等),那么这种情况下所需要的苹果数之和是:
totalEquidifference := bigSum + smallSum + small*(big-small) + big + 1
-
边界2:小边是从1开始的等差的情况,所以大边的情况应该是和小边情况一样,所以这种情况下所需要的苹果数之和是:
smallEquidifference := smallSum*2 + small + 1
详解如图:
根据两个边界可以得出几种情况:
-
大于边界1
小明的苹果数:maxApples = big + 1 + (m-totalEquidifference)/n + 1
边界1时小明苹果数为big+1+1(后面的1是初始没人都有一个苹果),接下来每多n个苹果就每人加1,且只有第n个才是小明的, -
等于边界1
maxApples = big + 1 + 1
边界1时小明苹果数为big+1+1(后面的1是初始没人都有一个苹果) -
边界1与边界2之间
maxApples = small + int(math.Sqrt(float64(2*(m-smallEquidifference)+((3+2*small)/2)*(3+2*small)))) - (3+2*small)/2 + 1
-
等于边界2
maxApples = small + 1
边界2时小明苹果数为small+1+1(后面的1是初始没人都有一个苹果)
10.小于边界2
maxApples = int(math.Sqrt(float64(m))) - 1
整体过程可能有点复杂,但主要思路就是找到边界然后在根据边界划分不同区域,在同一区域内数据变化是一致的,即可以计算的,那么就可以根据边界判断适合那种公式,从而计算得出结果。