145
社区成员
发帖
与我相关
我的任务
分享1、概括第四章学习内容,总结第四章学习心得
贪心算法
定义:贪心算法又称贪婪算法,常用于优化问题近似解的求解。贪心算法求解过程特点:从问题的初始状态出发,通过若干次贪心选择而得出问题最优解(或较优解)的一种计算机解题方法。
特点:贪心法在解决问题的策略上“目光短浅”,只根据当前已有的求解信息就做出局部最优选择,而且一旦做出了选择,不管将来有什么结果,这个选择都不会改变。贪心法每次所做出的选择只是在某种意义上的局部最优选择,这种局部最优选择并不总能保证获得问题的整体最优解,但通常能获得近似最优解。在众多的计算机算法中,贪心策略是最接近人们日常思维的一种解题策略。
可采用贪心算法求解问题的特征:(1)最优子结构性质:一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质,也称此问题满足最优性原理。这是贪心算法可行的第一个基本要素。最优子结构性质是某问题可用动态规划算法或贪心算法求解的关键特征。(2)贪心选择性质:贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择(贪心选择)得到。这是贪心算法可行的第二个基本要素,也是贪心算法与动态规划算法的主要区别。贪心算法通常以自顶向下的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题,然后再求解一次贪心选择后产生的子问题解。一个具体问题,要确定它是否具有贪心选择性质,须证明每一步所作的贪心选择最终导致问题的整体最优解。
贪心算法的一般框架:
Greedy(A, n) // A[1:n]代表n个输入
{
Sort(A)
solution={}; //解向量初始化为空集
for i=1 to n do
xi:=Select(A)
if Feasible(solution, xi) then solution:=Union(solution, xi)
A=A-xi
end if
End for
Return (solution)
}
贪心算法设计要点:(1)按照贪心选择策略对数据进行预处理(排序);(2)贪心法求解过程是多步局部最优选择的判断过程,最终的贪心选择序列对应于问题解;(3)局部最优选择判断依据某种贪心选择策略,贪心选择策略的好坏决定算法成败;(4)贪心选择性质须进行正确性证明。
贪心算法求解步骤:按照贪心选择策略对数据进行预处理(排序);从问题初始状态开始;采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,贪心地得到一个部分解,并缩小问题范围或规模;将所有部分解综合起来,得到问题的最终解。
心得:贪心算法的优势:算法简单,时间和空间复杂性低。
2、以{0-1}背包问题和背包问题为例,讨论动态规划算法与贪心算法的异同。
0-1背包问题在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包。不能装入多次,也不能只装入部分物品。背包问题与0-1背包问题相似,不同的是可以选择物品的一部分,而不一定全部装入背包。这2类背包问题都具有最优子结构性质,极为相似,但背包问题可用贪心算法求解得到最优解,0-1背包问题却不能用贪心算法求解。
对于0-1背包问题,贪心选择不能得到最优解。因为在这种情况下,算法无法保证最终能将背包装满,部分闲置背包空间使每公斤背包空间的价值降低。动态规划算法在考虑0-1背包问题时,比较了选择该物品和不选择该物品的所有可能方案,最后在所有方案中找出最好选择。并导出许多互相重叠的子问题。这正是该问题用动态规划算法求解的一个重要特征。
共同点:贪心算法和动态规划算法都要求问题具有最优子结构性质,这是2类算法的一个共同点。
不同点:动态规划法通常以递推方式求解各个子问题,某个子问题的解依赖于已知子问题的最优解再作出选择。贪心算法通常以一系列的局部贪心选择和求解,每个局部阶段,先作贪心选择,再解子问题。
3、算法实验2:完成教材114页算法实现题4-2,总结实验出现问题及解决方法。
问题描述
给定k个排好序的序列s1,s2,...,sk,用2路合并算法将这k个序列合并成一个序列。假设采用的2路合并算法合并2个长度分别为m和n的序列需要m+n-1次比较。试设计一个算法确定合并这个序列的最优合并顺序,使所需的总比较次数最少。为了进行比较,还需要确定合并这个序列的最差合并顺序,使所需的总比较次数最多。
问题求解
def Maximum(num):
num1 = num.copy()
num1.sort(reverse=True)
print(num1)
fulltimes = 0 # 总的比较次数
times = 0 # 每两个序列的比较次数
for i in range(n - 2):
# 取序列长度最长的两个序列先进行比较
times = num1[0] + num1[1]
fulltimes = fulltimes + times - 1
# 删除已比较的序列
del num1[0]
del num1[0]
# 加入合并后的序列
num1.append(times)
num1.sort(reverse=True)
times = num1[0] + num1[1] - 1
fulltimes = fulltimes + times
return fulltimes
def Minimum(num):
num2 = num.copy()
# 将列表num2升序排列
num2.sort()
print(num2)
Times = 0 # 总的比较次数
times = 0 # 每两个序列的比较次数
for i in range(n - 2):
# 取序列长度最短的两个序列先进行比较
times = num2[0] + num2[1]
Times = Times + times - 1
# 删除已比较的序列
del num2[0]
del num2[0]
# 加入合并后的序列
num2.append(times)
num2.sort()
times = num2[0] + num2[1] - 1
Times = Times + times
return Times
# 从文件中读出数据
file_readpath = 'input.txt'
with open(file_readpath) as file:
txt = file.read()
txt = txt.split('\n')
# n代表数据的个数
n = eval(txt[0])
num = []
txt = txt[1].split()
for i in range(n):
num.append(eval(txt[i]))
# 输出结果用于验证
maximum = Maximum(num)
# print(duo)
minimum = Minimum(num)
# print(Shao)
print("最多次数为:", maximum)
print("最少次数为:", minimum)
# 将结果存入文件output.txt
file_writepath = 'output.txt'
file = open(file_writepath, "w")
file.write(str(maximum) + ' ' + str(minimum))
file.close()
运行结果:



n = int(input("请输入需要合并的石子堆数:"))
k = int(input("请输入每次最多合并的石子堆数:"))
arr=input("请输入每堆石子的个数:")
p =[int(i) for i in arr.split()]
p.sort()
#最大总费用
max = 0
max1 = p[n-1]
for i in range(n-2,-1,-1):
if p[i] == 0:
break
max1 += p[i]
max += max1
#最小总费用
i = 0
min = 0
min1 = 0
while i < n-1:
min1=0
p = p + [0]
for j in range(0, k):
min1+=p[i]
i+=1
p[n]=min1
n+=1
min+=min1
#将i-n部分排序
p[i:n] = sorted(p[i:n])
print("最大总费用为:", max, "\n最小总费用为:", min)
运行结果:
