贪心算法

贪心算法

特征:

• 在对问题求解时,总是做出在当前看来是最好的选择
• 基本思路:
  • 建立数学模型来描述问题。
  • 把求解的问题分成若干个子问题。
  • 对每一子问题求解,得到子问题的局部最优解。
  • 把子问题的解局部最优解合成原来解问题的一个解。
• 贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
• 基本要素:
  •  贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择 (贪心算法与动态规划算法的主要区
     别,动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的
     方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。)
  • 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该
    问题可用动态规划算法或贪心算法求解的关键
 
一、找硬币
ž 设有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
个正方形,使得断开成本最小。每个板的切割成本将提供给电路板。总
之,我们需要选择这样的一系列切割,以使成本最小化。
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

 

 
posted @ 2020-06-11 10:27  oldby  阅读(373)  评论(0编辑  收藏  举报