19948: 因材施教
greedy, http://cs101.openjudge.cn/practice/19948
有一所魔法高校招入一批学生,为了贯彻因材施教的理念,学校打算根据他们的魔法等级进行分班教育。在确定班级数目的情况下,班级内学生的差异要尽可能的小,也就是各个班级内学生的魔法等级要尽可能的接近。 例如:现在有(n = 7)位学生,他们的魔法等级分别为(r = [2, 7, 9, 9, 16, 28, 45]),我们要将他们分配到(m = 3)个班级,如果按照([2, 7], [9, 9], [16, 28, 45])的方式分班,则他们的总体差异为(d = (7 - 2) + (9 - 9) + (45 - 16) = 34)。
输入
第一行为两个整数:学生人数n和班级数目m,1 <= m <= n <= 10^5。 第二行为n个整数:每位学生的魔法等级ri,1 <= ri <= 10^9。
输出
一个整数:学生的最小总体差异d。
样例输入
Sample1 Input
7 3
2 7 9 9 16 28 45
Sample1 Output
14
解释:最小总体差异的分班方式为([2, 7, 9, 9, 16], [28], [45])样例输出
Sample2 Input
15 9
90 73 116 47 400 212 401 244 13 372 248 56 194 482 177
Sample2 Output
65
解释:最小总体差异的分班方式为([13], [47, 56, 73, 90], [116], [177, 194], [212], [244, 248], [372], [400, 401], [482])来源:cs101 2019 Final Exam
思路:本质就是去掉m-1个最大的差值。先升序排序魔法等级,再按照差值逆序排。
n,m = map(int,input().split())
r = [int(x) for x in input().split()]
r.sort()
rd = []
for i in range(len(r)-1):
rd.append(r[i+1] - r[i])
rd.sort(reverse=True)
d = sum(rd)
for i in rd:
d -= i
m -= 1
if m==1:
break
print(d)思路:无论怎么分班,最后的总体差异一定是 n-m个两两差异的和,将列表排序后两两作差,再将两两差异排序,取前 n-m个数之和即为答案取前 n-m个数之和即为答案。
n个数俩俩做差得n-1个差,其中最大的m-1个差单独分班,剩余的分到一个班(n-1-(m-1))=n-m.
n,m = map(int,input().split())
r = [int(x) for x in input().split()]
r.sort()
rd = []
for i in range(len(r)-1):
rd.append(r[i+1] - r[i])
rd.sort()
print(sum(rd[:n-m]))2021fall-cs101,黄章毅。又是非常巧妙的greedy,主要是在于分组之后内部的信息就是无用的了,正如在ants 一题中蚂蚁究竟是哪只蚂蚁并无影响,贪心方法的重点就是在于抓住问题的主要特点而忽略其次要因素,在解题时不能一味地只考虑计算机思维,一味地去模拟整个过程,还应该看一看能不能把问题抽象来看,去思考有没有数学上更加巧妙的算法。