贪心算法
贪心算法
特征:
• 在对问题求解时,总是做出在当前看来是最好的选择
• 基本思路:
• 建立数学模型来描述问题。
• 把求解的问题分成若干个子问题。
• 对每一子问题求解,得到子问题的局部最优解。
• 把子问题的解局部最优解合成原来解问题的一个解。
• 贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
• 基本要素:
• 贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择 (贪心算法与动态规划算法的主要区
别,动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的
方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。)
• 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该
问题可用动态规划算法或贪心算法求解的关键
一、找硬币
设有n 种不同面值的硬币,各硬币的面值存于数组T〔1:n 〕中。现要
用这些面值的硬币来找钱。可以使用的各种面值的硬币面值{1,2,5
,10,20,50,100,500,1000} 对任意钱数0≤m≤20001,设计一个用
最少硬币找钱 的方法。
def minCoins(V): available = [1, 2, 5, 10, 20, 50, 100, 500, 1000] result = [] for i in available[::-1]: while (V >= i): V -= i result.append(i) return result
二、活动问题
N个活动,每个活动的开始时间为si,结束时间是fi。如果 si ≥ fj or sj ≥ fi则可以定义这两场活动不冲突。试着找到一种能够找到最多的非冲突
活动的集合(S)。也就是说无法找到集合S’ 使得|S’| > |S|。
def printMaxActivities(acts): n = len(acts) sort_acts = sorted(acts, key=lambda tup: tup[1]) prev = sort_acts[0] print(prev) for curr in sort_acts: if curr[0] >= prev[1]: print(curr) prev = curr
三、最小的数字问题
如何找到给定数字总和s和位数m的最小数字?
• 输入: s = 9,m = 2
• 输出: 18
• 还有许多其他可能的数字,如45,54,90等,数字总和为9,数字位数为2.
其中最小的为18。
• 输入: s = 20,m = 3
• 输出: 299
def findSmallest(m, s): if (s == 0): if(m == 1) : print("Smallest number is 0") else : print("Not possible") return # 9999 if (s > 9 * m): print("Not possible") return res = [0 for i in range(m + 1)] # deduct sum by one to account for cases later # (There must be 1 left for the most significant digit) s -= 1 for i in range(m-1,0,-1): # If sum is still greater than 9, digit must be 9. if (s > 9): res[i] = 9 s -= 9 else: res[i] = s s = 0 res[0] = s + 1 print("Smallest number is ",end="") for i in range(m): print(res[i],end="")
四、两个数字的最小和
给定一个数字数组(数值从0到9),找出由数组数字形成的两个数字的最小可能和。给定数组的所有数
字必须用于形成两个数字。
• 输入:[6,8,4,5,2,3]
• 输出:604
• 最小总和由数字组成
• 358和246
• 输入:[5,3,0,7,4]
• 输出:82
• 最小总和由数字组成
• 35和047
import heapq def minSum(a): heapq.heapify(a) num1 = 0 num2 = 0 while a: num1 = num1 * 10 + heapq.heappop(a) if a: num2 = num2 * 10 + heapq.heappop(a) return num1 + num2
五、以最低的成本连接绳索
• 有n条不同长度的绳索,我们需要将这些绳索连接成一根绳子。连接两条绳
索的成本等于它们长度的总和。我们需要以最低的成本连接绳索。
• 例如,如果我们获得4条长度为4,3,2和6的绳索,我们可以通过以下方式
连接绳索。
1)首先连接长度为2和3的绳索。现在我们有三根长度为4,6和5的绳索。
2)现在连接长度为4和5的绳索。现在我们有两根长度为6和9的绳索。
3)最后连接两条绳索,所有绳索已连接。
• 连接所有绳索的总成本为5+9+15=29。
import heapq def ropeCost(ropes): heapq.heapify(ropes) total = 0 while ropes: first = heapq.heappop(ropes) second = heapq.heappop(ropes) local = first + second total += local if not ropes: break heapq.heappush(ropes, local) return total
六:最小平台数
根据所有到达火车站的列车的到达和离开时间,找到火车站所需的最少数量的平台,以免列车等待。
• 我们给出了代表停止列车到达和离开时间的两个数组
• 例子:
• 输入:arr [] = {9:00, 9:40, 9:50, 11:00, 15:00, 18:00}
•
dep [] = {9:10, 12:00, 11:20, 11:30, 19:00, 20:00}
• 输出:3
• 一次最多有三班列车(时间为11:00至11:20)
def findPlatform(arr, dep, n): arr.sort() dep.sort() # plat_needed indicates number of platforms needed at a time plat_needed = 0 result = 0 i = 0 j = 0 # Similar to merge in merge sort to process all events in sorted order while (i < n and j < n): if (arr[i] < dep[j]): plat_needed += 1 i += 1 result = max(result, plat_needed) else: plat_needed -= 1 j += 1 return result
七、部分背包问题
• 给定n个项目的权重和值,我们需要把这些项目放入W的背包中,
以获得背包中最大的总价值。
• 在0-1背包问题中,我们不允许分解物品。我们要么拿整个项目
,要么不拿。
• 在分数背包中,我们可以打破物品以最大化背包的总价值。这个
问题,我们可以打破项目也被称为分数背包问题。
def fracKnapsack(capacity, weights, values): numItems = len(values) valuePerWeight = sorted([[v / w, w, v] for v,w in zip(values,weights)], reverse=True) print(valuePerWeight) totalCost = 0. for tup in valuePerWeight: if capacity >= tup[1]: capacity -= tup[1] totalCost += tup[2] else: totalCost += capacity * tup[0] break return totalCost
八、将板子切割成正方形的最小成本
• 给定一个长度为m和宽度为n的电路板,我们需要将这个电路板分成m*n
个正方形,使得断开成本最小。每个板的切割成本将提供给电路板。总
之,我们需要选择这样的一系列切割,以使成本最小化。
![](https://img2020.cnblogs.com/blog/1509441/202006/1509441-20200611101548875-1292149942.png)
def minimumCostOfBreaking(X, Y, m, n): res = 0 # sort the horizontal cost in reverse order X.sort(reverse = True) # sort the vertical cost in reverse order Y.sort(reverse = True) # initialize current width as 1 hzntl = 1; vert = 1 # loop untill one or both # cost array are processed i = 0; j = 0 while (i < m and j < n): if (X[i] > Y[j]): res += X[i] * vert # increase current horizontal # part count by 1 hzntl += 1 i += 1 else: res += Y[j] * hzntl # increase current vertical # part count by 1 vert += 1 j += 1 # loop for horizontal array, if remains total = 0 while (i < m): total += X[i] i += 1 res += total * vert #loop for vertical array, if remains total = 0 while (j < n): total += Y[j] j += 1 res += total * hzntl return res
九、字典中最小的数组
• 给定一个数组arr[ ],找到在最多K次连续交换之后可以获得的字典顺序最小的数组。
• 输入:
• arr = [7,6,9,2,1], k = 3
• 输出:arr = [2,7,6,9,1]
• 说明:
数组是:7,6,9,2,1
交换1:7,6,2,9,1
交换2:7,2,6,9,1
交换3:2,7,6,9,1
所以我们在k = 3交换后的最后一个数组:
2,7,6,9,1
def minimizeWithKSwaps(arr, n, k): for i in range(n-1): pos = i for j in range(i+1, n): # If we exceed the Max swaps then terminate the loop if ( j - i > k): break # Find the minimum value from i+1 to max (k or n) if (arr[j] < arr[pos]): pos = j # Swap the elements from Minimum position we found till now to the i index for j in range(pos, i, -1): arr[j],arr[j-1] = arr[j-1], arr[j] # Set the final value after swapping pos-i elements k -= pos - i