首页 > 编程语言 >【技术积累】算法中的贪心算法【二】

【技术积累】算法中的贪心算法【二】

时间:2023-06-09 10:23:51浏览次数:35  
标签:积累 sum selected 任务 算法 最优 贪心

如何证明一个问题可以使用贪心算法解决?

判断一个问题是否可以使用贪心算法解决,通常需要满足两个条件:

  1. 贪心选择性质:问题的最优解可以通过一系列局部最优解得到。也就是说,在每一步选择中,都选择当前最优解,而不考虑之后的影响。
  2. 最优子结构性质:问题的子问题的最优解可以推导出原问题的最优解。也就是说,问题的子问题的最优解可以重复利用,从而得到原问题的最优解。

因此,如果一个问题满足以上两个条件,就可以使用贪心算法解决。但是,需要注意的是,贪心算法得到的解不一定是全局最优解,而是局部最优解。因此,在使用贪心算法时,需要根据具体问题来判断是否能够得到全局最优解。

贪心算法的时间和空间复杂度是什么?

贪心算法的时间复杂度通常是O(n log n)或O(n),其中n是问题的规模。

空间复杂度通常是O(1),因为贪心算法通常只需要存储一些变量来跟踪最优解。

以下是一个例子,展示如何使用贪心算法解决集合覆盖问题:

假设有一个需要覆盖的集合,以及一些可用于覆盖集合的子集。我们的目标是找到最少的子集,以便覆盖整个集合。

set_cover(sets, universe):
  # Initialize the empty list of selected sets
  selected_sets = []
  # Create a copy of the universe to track remaining elements
  remaining_elements = set(universe)
  # Continue until all elements are covered
  while remaining_elements:
    # Select the set that covers the most remaining elements
    best_set = max(sets, key=lambda s: len(s & remaining_elements))
    # Add the selected set to the list of selected sets
    selected_sets.append(best_set)
    # Update the remaining elements to exclude those covered by the selected set
    remaining_elements -= best_set
  return selected_sets

在这个例子中,时间复杂度为O(n log n),其中n是集合的大小。空间复杂度为O(n),因为我们需要存储所有的子集和剩余元素。

使用贪心算法时有哪些常见陷阱? 

使用贪心算法时,常见的陷阱有以下几点:

  1. 局部最优解不一定是全局最优解:贪心算法通常只考虑当前步骤的最优解,而不是全局最优解。因此,如果贪心算法选择的局部最优解无法达到全局最优解,那么结果就会出现错误。
  2. 无法回溯:贪心算法做出的选择通常是不可逆的,因此一旦做出了错误的选择,就无法回溯到之前的状态进行修正。
  3. 需要正确性证明:虽然贪心算法通常很简单,但是在某些情况下,它可能会给出错误的结果,因此需要进行正确性证明。

以下是一个贪心算法的案例,用来说明常见的陷阱: 假设有一个背包,可以装载重量为W的物品。现在有n个物品,每个物品有一个重量w和一个价值v。我们的目标是选择一些物品,使得它们的总重量不超过W,并且它们的总价值最大。

伪代码如下:

GreedyKnapsack(W, w[], v[], n):
    // W为背包容量,w[]为物品重量,v[]为物品价值,n为物品数量
    totalValue = 0
    for i = 1 to n:
        if w[i] <= W:
            // 选择当前物品
            totalValue += v[i]
            W -= w[i]
        else:
            // 当前物品无法装入背包
            totalValue += (v[i] / w[i]) * W
            break
    return totalValue

如何证明贪心算法的最优性?

要证明贪心算法的最优性,通常需要使用数学归纳法或反证法。下面是一个简单的例子,展示如何使用数学归纳法证明贪心算法的最优性:

问题:假设你有n个任务,每个任务有一个开始时间和结束时间。你想要找到一种方法,使你能够完成尽可能多的任务,而不会出现时间冲突。

贪心算法:按照任务的结束时间对任务进行排序,然后从第一个任务开始,依次选择结束时间最早的任务,直到所有任务都完成。

证明:我们使用数学归纳法证明贪心算法的最优性。

基本情况:当n=1时,贪心算法显然是最优的。

归纳假设:假设当n=k时,贪心算法是最优的。

归纳步骤:

  1. 考虑n=k+1的情况。
  2. 我们将任务按照结束时间排序,然后依次选择结束时间最早的任务。
  3. 假设我们选择了任务i作为第一个任务,那么我们需要找到剩余任务中结束时间最早的任务j。
  4. 由于任务i结束时间最早,所以任务j的开始时间一定晚于任务i的结束时间。
  5. 我们可以将任务j从剩余任务中删除,然后继续在剩余任务中选择结束时间最早的任务。
  6. 由于我们已经删除了一个任务,所以剩余任务的数量为k。
  7. 根据归纳假设,我们知道贪心算法在k个任务上是最优的。因此,我们可以使用贪心算法来完成这k个任务,而不会出现时间冲突。
  8. 由于任务i和任务j没有时间冲突,所以我们可以将它们一起完成。
  9. 因此,贪心算法也是在n=k+1个任务上是最优的。
  10. 因此,根据数学归纳法,我们证明了贪心算法的最优性。

下面是一个使用伪代码实现的例子:

Sort tasks by their end times
selected_tasks = []
last_end_time = 0
for task in tasks:
    if task.start_time >= last_end_time:
        selected_tasks.append(task)
        last_end_time = task.end_time
return selected_tasks


在这个例子中,我们首先将任务按照结束时间进行排序。然后,我们从第一个任务开始,依次选择结束时间最早的任务。如果我们选择的任务的开始时间晚于上一个任务的结束时间,那么我们将该任务添加到已选择的任务列表中,并将其结束时间设置为last_end_time。最后,我们返回已选择的任务列表。

贪心算法和动态规划算法有什么区别?

贪心算法和动态规划算法的区别在于它们解决问题的方式和适用范围不同。

贪心算法通常使用贪心选择性质和最优子结构性质来解决问题,每一步都选择当前最优解,并且不回溯之前的选择。因此,贪心算法的时间复杂度通常较低,但是它无法保证得到全局最优解,因为它只考虑了当前步骤的最优解,而没有考虑之后步骤的影响。贪心算法适用于一些特定类型的问题,如最小生成树、最短路径、背包问题等。

动态规划算法则是一种将问题分解成子问题并重复利用已经计算出的结果的方法。它通常需要使用记忆化搜索或者自底向上的迭代方法来求解问题。动态规划算法的时间复杂度通常比贪心算法高,但是它能够保证得到全局最优解。动态规划算法适用于那些具有最优子结构性质和重叠子问题的问题,如背包问题、最长公共子序列、最长递增子序列等。

在效率方面,贪心算法通常更高效,因为它只需要考虑当前步骤的最优解,而不需要回溯之前的选择。因此,贪心算法的时间复杂度通常较低,适用于一些特定类型的问题,如最小生成树、最短路径、背包问题等。

在准确性方面,贪心算法得到的解不一定是全局最优解,而是局部最优解。因此,在某些情况下,贪心算法无法保证得到全局最优解,动态规划算法可以保证得到全局最优解。

因此,在选择算法时,需要根据具体问题的特点来选择合适的算法,以达到最优的效果。

贪心算法求解最小顶点覆盖问题

给定一个无向图G=(V,E),寻找最小的顶点集合S,使得对于每一条边(u,v)∈E,至少有一个端点属于S。

  1. 初始化顶点集合S为空集。
  2. 对于每条边(u,v)∈E,如果u和v都没有被覆盖,则将u和v中任意一个顶点加入集合S中。
  3. 重复步骤2,直到所有的边都至少有一个端点被覆盖。
  4. 返回集合S。
VertexCover(G):
    S = empty set
    for each edge (u, v) in E:
        if u is not in S and v is not in S:
            add any vertex from {u, v} to S
    return S

贪心算法求解最小路径覆盖问题?

给定一个有向无环图G=(V,E),寻找最小的路径集合P,使得每个顶点恰好出现在一条路径中。

  1. 将有向无环图G转化为一个二分图G'=(V',E'),其中V'={u,v|u,v∈V},对于每个顶点v∈V,将其拆分为两个顶点u,v',其中u表示顶点v作为起点的路径,v'表示顶点v作为终点的路径。
  2. 在二分图G'上运行最大匹配算法,得到最大匹配M。
  3. 对于每个未匹配的顶点u∈V,将其作为起点的路径加入路径集合P中。
  4. 对于每个匹配的边(u,v')∈M,将路径u->v'加入路径集合P中。
  5. 返回路径集合P。
MinimumPathCover(G):
    G' = transform G into a bipartite graph
    M = find maximum matching in G'
    P = empty set
    for each vertex u in V:
        if u is not matched in M:
            add path u to P
    for each edge (u, v') in M:
        add path u->v' to P
    return P

贪心算法求解最大子矩阵问题?

给定一个n行m列的矩阵A,矩阵中的元素为整数。寻找一个子矩阵B,使得B中所有元素之和最大。

  1. 对于每一行i∈[1,n],计算以第i行为底部的矩阵中每列的元素之和,得到一个长度为m的一维数组sum。
  2. 对于每一对行i,j∈[1,n],计算以第i行和第j行为底部的矩阵中每列的元素之和,得到一个长度为m的一维数组diff,其中diff[k]=sum[k]-A[i][k]-A[j][k]。
  3. 对于数组diff,使用最大子序列和算法求解最大子矩阵的列范围。设最大子矩阵的列范围为[l,r]。
  4. 对于每一行i∈[1,n],计算以第i行为底部,列范围为[l,r]的矩阵中所有元素之和,取所有结果中的最大值。
  5. 返回最大子矩阵的元素之和。
MaximumSubmatrix(A):
    n, m = dimensions of A
    max_sum = -infinity
    for i from 1 to n:
        sum = array of length m, initialized to 0
        for j from i to n:
            for k from 1 to m:
                sum[k] += A[j][k]
            diff = array of length m-1, initialized to 0
            for k from 1 to m-1:
                diff[k] = sum[k+1] - sum[k] - A[i][k] - A[j][k]
            [l, r] = find maximum subarray of diff
            row_sum = 0
            for k from l to r:
                row_sum += sum[k] - A[i][k] - A[j][k]
            max_sum = max(max_sum, row_sum)
    return max_sum

 

标签:积累,sum,selected,任务,算法,最优,贪心
From: https://www.cnblogs.com/yyyyfly1/p/17468409.html

相关文章

  • 3. 密码算法和密码消息的ASN.1描述(openssl应用举例)
    密码算法和密码消息的ASN.1描述(openssl应用举例)目录密码算法的描述密码算法的ASN.1格式密码算法的OID密码消息的描述密码消息的ASN.1描述通用内容消息的格式Data的格式SignedData的格式SignerInfo的格式EnvelopedData的格式SignedAndEnvelopeDdata的格式Dige......
  • 【技术积累】算法中的贪心算法【一】
    贪心算法是什么贪心算法是一种常见的算法思想,主要应用于优化问题中,特别是在计算机科学和运筹学领域中。贪心算法的核心思想是每一步都选择当前最好的选项,从而得到全局最优解。贪心算法通常包括以下步骤:确定问题的最优子结构:即在问题中寻找那些可以自行解决的子问题。开始......
  • 【数据结构与算法】算法的时间复杂度和空间复杂度
    前言关于时空复杂度的分析,是每一个程序员的必备技能,本文将带你了解什么是时空复杂度?熟知怎样去计算一个算法的时间复杂度和空间复杂度。1.算法效率1.1.如何衡量一个算法的好坏如何衡量一个算法的好坏呢?我们先看一段代码:intFib(intN){if(N<3)return1;......
  • 安卓逆向 -- Frida Hook某车_sign算法分析
    接上节课内容安卓逆向--Frida环境搭建(HOOK实例)安卓逆向--FridaHook某车udid的加密值安卓逆向--FridaHook分析3DES加密值安卓逆向--SO文件逆向分析一、上节课抓包有个sign值二、用jadx打开,全局搜索"_sign",发现sign值都来自于toSign函数三、查找toSign函数声明的地方public......
  • 180116 EM算法资料整理(博客、论文、工具包、视频、书籍、代码,更新ing)
    BlogsHindon和Jordan理解的EM算法ComputationalStatisticsinPythonEM算法及其推广EM算法及其推广学习笔记从最大似然到EM算法浅解EM算法在缺失数据下的极大似然估计R代码Matlab极大似然估计缺失数据Cos424:InteractingwithDataProbabilityCourse关于EM算法的一些......
  • 文心一言 VS 讯飞星火 VS chatgpt (35)-- 算法导论5.3 5题
    五、证明:在过程PERMUTE-BY-SORTING的数组P中,所有元素都唯一的概率至少是1-1/n。文心一言:证明:在过程PERMUTE-BY-SORTING中,对于输入数组P中的每个元素,其出现次数为1,因此对于每个元素,在排序后的数组中,它出现的位置是唯一的。假设在排序后的数组中,有两个元素a和b,它们在原始数组......
  • 【计算机视觉】基于纹理特征的指纹识别位置与姿态算法
    简介计算机视觉基于纹理特征的指纹识别中的位置和姿态估计是指确定指纹图像中指纹的位置和方向的过程。这些信息对于后续的特征提取和匹配非常重要。下面介绍两个常用的算法来实现位置和姿态的估计:方向图和边界框。方向图(OrientationMap)方向图(OrientationMap)是用来表示指纹图像中......
  • 得到第K个大的数算法研究
      第一种算法是最容易想到的,就是利用快速排序的思想,将一个数组分成以某一个数X为轴,左边的所有的数都比X小,而右边的数都比X大。但我快速排序不同的是,在这个算法中只考虑X的一边,而不是两边都考虑。 如果X的位置是i,那么要得到第k个数,如果k<=i,那么这个数一定在i的左边,否则在i......
  • 从零开始学Java之查找算法有哪些?
    前言在前面的两篇文章中,给大家介绍了常见的排序算法,除此之外,其实还有查找算法也需要我们掌握。接下来就来给大家讲讲都有哪些查找算法,以及经典的二分查找法该如何实现。全文大约【3000】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更......
  • 医疗图像方向硕士,焦虑发论文毕业,咨询好的CV算法方向,与同门如何合作?
    第一、目前CV算法哪个方向好发文章,怎么快速准备并上手赶出论文?这个问题不是特别好准确回答,因为CV算法是一个非常大研究领域,包括目标检测,图像分割,图像生成,3D目标检测,三维图像重建,图像去雾,图像超分辨率等非常多的方向。你会这么问,我的感觉是你对其中哪个方向研究都不会很深,因为你是......