题目描述
有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 main
import (
"fmt"
"math"
"os"
)
// maxApplesForXiaoming 使用贪心策略计算小明最多能分到的苹果数
func maxApplesForXiaoming(m, n, k int) int {
// 初始化小明最多能分到的苹果数为1
maxApples := 1
// 如果只有一个小孩,直接返回所有苹果
if n == 1 {
return m
}
if m < n {
return -1
}
m = m - n
var big int
var small int
if (k - 1) > (n - k) {
big = k - 1
small = n - k
} else {
big = n - k
small = k - 1
}
// 确定小明的位置相对于序列长度的位置
// 计算从左到小明处能分配的苹果数(等差数列求和)
bigSum := (big * (big + 1)) / 2
smallSum := (small * (small + 1)) / 2
totalEquidifference := bigSum + smallSum + small*(big-small) + big + 1
smallEquidifference := smallSum*2 + small + 1
switch true {
case m > totalEquidifference:
maxApples = big + 1 + (m-totalEquidifference)/n + 1
return maxApples
case m == totalEquidifference:
maxApples = big + 1 + 1
return maxApples
case m < totalEquidifference && m > smallEquidifference:
maxApples = small + int(math.Sqrt(float64(2*(m-smallEquidifference)+((3+2*small)/2)*(3+2*small)))) - (3+2*small)/2 + 1
return maxApples
case m == smallEquidifference:
maxApples = small + 1
case m < smallEquidifference:
maxApples = int(math.Sqrt(float64(m))) - 1
return 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
整体过程可能有点复杂,但主要思路就是找到边界然后在根据边界划分不同区域,在同一区域内数据变化是一致的,即可以计算的,那么就可以根据边界判断适合那种公式,从而计算得出结果。