【数据结构】贪心算法

news2024/12/25 8:51:16

一.贪心算法的定义

        贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解

        贪心算法的结果是最优解的最好近似。

优点:简单,高效。

缺点:可能不是正确的或最优的解

二.引例

当一个问题具有最优子结构性质时,可以用动态规划求解。也可以用贪心算法来求解。

哈夫曼编码:每次选择集合中权值最小的两个子树构成一棵树。

思想:贪心选择思想。

三.贪心算法的基本步骤与实现

1.建立数学模型来描述问题;

2.把求解的问题分成若干个子问题;

3.对每一个子问题求解,得到子问题的局部最优解;

4.把子问题的局部最优解合成原来问题的解。

四.贪心算法的应用

1.活动安排问题

(1)问题描述

1)有n个活动;

2)活动j在$s_j$时刻开始,$f_j$时刻结束;

3)如果两个活动不重叠,则这两个活动是可以兼容的;

4)目标:找到相互兼容的最大活动子集

(2)活动相容性:

设有n个活动的集合E={1,2,……,n},其中,每个活动都要求使用同一资源,如会场等。

而在同一时间内,只有一个活动能够使用该资源。

每个活动i都有一个要求使用该资源的起始时间$s_i$和一个结束时间$f_i$,且$s_i$<$f_i$

如果选择了活动i,则它在半开时间区间[$s_i$,$f_i$)内占用资源。

若区间[$s_i$,$f_i$)与区间[$s_j$,$f_j$)不相交,则称活动i与活动j相容。

(3)贪心策略:

先安排结束时间最早的活动,可以使得剩余的时间极大化,从而安排更多的活动。

(4)伪代码:

1.将所有活动按照结束时间从小到大排列;

2.扫描所有活动的开始时间与结束时间,若扫描到活动i的开始时间早于最近安排的活动j的结束时间,则不安排活动i,否则,安排活动i。

(5)代码:

int greedySelector(int s[],int f[],bool a[],int n){
    //n代表事件个数,bool类型的数组a表示活动i是否被安排
    //各活动的起始时间和结束时间存储于数组s和f中且按结束时间的非减序排序
    int i=0,j=0,count=0;//i表示处理的第i个活动,j表示刚刚安排的活动,count记录安排活动的数量
    //初始化
    a[i]=true;//安排第一个事件
    j=0;
    count++;
    for(i=1;i<n;i++){
        if(s[i]>f[j]) {
            a[i]=true;
            j = i;
            count++;
        }
        else{
            a[i]=false;
        }
    }
    return count;
}

 

(6)其他贪心策略:

1)最早开始时间

按照开始时间$s_i$非递减排序

2)最早结束时间 

按照结束时间$s_i$非递减排序

3)最短间隔

按照间隔长度$f_i-s_i$非递减排序

4)最小冲突

对于每个活动,计算该活动的冲突活动数$c_j$,并按照$c_j$非递减排序

(7)证明贪心算法对于活动安排问题的求解是整体最优解:

对于活动安排问题来说:

最优解即为:使得相容集合的规模最大

数学归纳法进行证明)

证明:

设E={1,2,……,n}活动集合(集合有序)

且按照活动安排结束时间递增排序,即:活动1具有最早的完成时间

假设:活动安排中有一个包含贪心选择的最优解

设A$\subseteq$E是该问题的一个最优解,且集合A也有序,对于A中的活动,将其表示为{$k_1,k_2,...,k_j$},则有活动的开始时间集合S={$s[k_1],s[k_2],...s[k_j]$},以及结束时间集合F=$\{f[k_1],f[k-2],...,f[k_j]\}$

找到一个集合A,首先:A是问题最优解;其次,A是贪心选择出来的集合。

当k=1时,A即为所求。

当k!=1时,设$B=$$A-\{k_1\}\cup\{1\}=\{1,k_2,k_3,...,k_j\}$

由于,$f[1]\leqslant f[k]$,将集合A更改之后,整个集合仍然相容,元素个数也没有改变,集合B也是最优解。

同理,以及将A中的元素替换,由于贪心选择的原理,每次选择结束时间最早的事件,则替换之后,集合仍然是相容的,将所有元素均替换为贪心选择的元素,则集合既是贪心选择的结果,也是最优解,即:贪心选择出的集合是最优解,得证。#

五.贪心算法的基本要素

1.贪心选择性质

所求问题的整体最优解可以通过一系列局部最优的选择达到。

用数学归纳法证明,通过每步的贪心选择,最终可以得到问题的整体最优解。

2.最优子结构性质

当一个问题的最优解包含其子问题的最优解,称此问题具有最优子结构性质。

问题的最优子结构性质是该问题可以用动态规划算法或者贪心算法求解的关键特征。

3.贪心算法和动态规划差别

动态规划:自底向上

贪心算法:从开始逐次迭代

0-1背包问题:

问题描述:

给定n种物品和一个背包。物品i的重量是$w_i $,其价值为$v_i$,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大。

背包问题:

问题描述:

与0-1背包问题类似,所不同的是,在选择物品i装入背包时,可以选择物品的一部分,而不一定要全部装入背包中。

这两类问题都具有最优子结构性质,但是背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。

用贪心算法求解背包问题的基本步骤:

1.计算每种物品单位重量的价值$\frac{v_i}{w_i}$;

2.依据贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包; 

3.若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包;

4.依照此策略一直进行下去,直到背包装满为止。

代码实现:

#include <iostream>
using namespace std;

struct node{
    float weight;
    float value;
    int number;
};

int greedySelector(int s[],int f[],bool a[],int n);
float knapsack(float c,int n,float v[],float w[],float x[]);
int partition(struct node a[],int first,int end);
void quickSort(struct node a[],int first,int end);


int main() {
    int n=5;
    float v[]={10,40,20,30,25};
    float w[]={15,12,8,9,10};
    float x[5];
    float c=21.5;
    knapsack(c,n,v,w,x);
    for(int i=0;i<n;i++){
        cout<<x[i]<<" ";
    }
    cout<<endl;
    return 0;
}

int greedySelector(int s[],int f[],bool a[],int n){
    //n代表事件个数,bool类型的数组a表示活动i是否被安排
    //各活动的起始时间和结束时间存储于数组s和f中且按结束时间的非减序排序
    int i=0,j=0,count=0;//i表示处理的第i个活动,j表示刚刚安排的活动,count记录安排活动的数量
    //初始化
    a[i]=true;//安排第一个事件
    j=0;
    count++;
    for(i=1;i<n;i++){
        if(s[i]>f[j]) {
            a[i]=true;
            j = i;
            count++;
        }
        else{
            a[i]=false;
        }
    }
    return count;
}

float knapsack(float c,int n,float v[],float w[],float x[]){
    //函数的返回值表示总价值
    //c表示背包容量
    //n表示物品个数
    //数组v表示价值value,数组w表示重量weight,数组x表示每个物品放入背包的比例
    struct node *p=new struct node[n];
    int i,j;
    float sum=0;
    for(i=0;i<n;i++){
        p[i].number=i;
        p[i].value=v[i];
        p[i].weight=w[i];
        x[i]=0;
    }
    quickSort(p,0,n-1);

    for(i=0;i<n;i++){
        if(p[i].weight>c){
            break;
        }
        else{
            x[p[i].number]=1;
            sum+=p[i].value;
            c-=p[i].weight;
        }
    }
    if(i<n){
        x[p[i].number]=c/p[i].weight;
        sum+=p[i].value*c/p[i].weight;
    }
    delete []p;
    return sum;
}

int partition(struct node a[],int first,int end){
    int i=first,j=end;
    struct node temp;
    while(i<j){
        while(i<j&&(a[j].value/a[j].weight)<=(a[i].value/a[i].weight)){
            --j;
        }
        if(i<j){
            temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
        while(i<j&&(a[j].value/a[j].weight)<=(a[i].value/a[i].weight)){
            ++i;
        }
        if(i<j){
            temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    return i;//i==j时,返回轴值
}

void quickSort(struct node a[],int first,int end){
    if(first<end){
        int pos=partition(a,first,end);
        quickSort(a, first, pos-1);
        quickSort(a, pos+1, end);
    }
}

贪心算法不适用于0-1背包问题:

对于0-1背包问题,贪心算法得不到最优解。

无法保证最终能够将背包装满,部分闲置的背包空间使得单位重量的价值变低了。

在考虑0-1背包问题时,应比较选择该物品和不选择该物品所导致的最终方案,然后再做出最好选择。由此导出了许多相互重叠的子问题,这正是利用动态规划求解的重要特征。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1307803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

慎用,Mybatis-Plus这个方法可能导致死锁

1 场景还原 1.1 版本信息 MySQL版本&#xff1a;5.6.36-82.1-log Mybatis-Plus的starter版本&#xff1a;3.3.2 存储引擎&#xff1a;InnoDB1.2 死锁现象 A同学在生产环境使用了Mybatis-Plus提供的 com.baomidou.mybatisplus.extension.service.IService#saveOrUpdate(T, co…

【MySQL】:表的约束(上)

表的约束 一.非空约束二.default约束三.列描述四.zerofill五.主键1.单个主键2.复合主键 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。比如有…

孩子还是有一颗网安梦——Bandit通关教程:Level 11 → Level 12

&#x1f575;️‍♂️ 专栏《解密游戏-Bandit》 &#x1f310; 游戏官网&#xff1a; Bandit游戏 &#x1f3ae; 游戏简介&#xff1a; Bandit游戏专为网络安全初学者设计&#xff0c;通过一系列级别挑战玩家&#xff0c;从Level0开始&#xff0c;逐步学习基础命令行和安全概念…

随机变量的定义

试验E的样本空间为S&#xff0c;样本空间S中的元素记为e&#xff0c;即样本点是e&#xff0c;样本空间记成&#xff0c;表示元素组成的集合。 随机变量的定义&#xff1a;设随机变量的样本空间为&#xff0c;是定义在样本空间S上的实值单值函数&#xff0c;称为随机变量。 随机…

螺旋矩阵算法(leetcode第54题)

题目描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a;输入&#xff…

《深入理解 Android ART 虚拟机》笔记

Dex文件格式、指令码 一个Class文件对应一个Java源码文件&#xff0c;而一个Dex文件可对应多个Java源码文件。开发者开发一个Java模块&#xff08;不管是Jar包还是Apk&#xff09;时&#xff1a; 在PC平台上&#xff0c;该模块包含的每一个Java源码文件都会对应生成一个同文件…

蝴蝶Butterfly 数据集VOC+yolo-2000张(labelImg标注)

蝴蝶被誉为“会飞的花朵”&#xff0c;是一类非常美丽的昆虫。蝴蝶大多数体型属于中型至大型&#xff0c;翅展在15~260毫米之间&#xff0c;有2对膜质的翅。体躯长圆柱形&#xff0c;分为头、胸、腹三部分。体及翅膜上覆有鳞片及毛&#xff0c;形成各种色彩斑纹。今天要介绍的是…

Mistral AI 推出高质量的稀疏专家混合AI人工智能模型——SMoE,有望超越ChatGPT3.5

Mistral AI&#xff08;“Mistral AI”是一家由前DeepMind和Meta Platforms&#xff08;META.US&#xff09;的研究人员组建的新公司。&#xff09;继续履行为开发者社区提供最佳开放模型的使命。他们发布了 Mixtral 8x7B&#xff0c;这是一个高质量的稀疏专家混合模型&#xf…

YOLOv8改进 | 2023主干篇 | 替换LSKNet遥感目标检测主干 (附代码+修改教程+结构讲解)

一、本文介绍 本文给大家带来的改进内容是LSKNet&#xff08;Large Kernel Selection, LK Selection&#xff09;&#xff0c;其是一种专为遥感目标检测设计的网络架构&#xff0c;其核心思想是动态调整其大的空间感受野&#xff0c;以更好地捕捉遥感场景中不同对象的范围上下…

【精选】SpringMVC简介及其执行流程,参数获取方式

SpringMVC简介 MVC模型 MVC全称Model View Controller&#xff0c;是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分&#xff1a; Model&#xff08;模型&#xff09;&#xff1a;指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中&…

37.分支结构嵌套

目录 一.什么是分支结构嵌套 二.什么情况下会用分支结构嵌套 三.举例 四.注意事项 五.视频教程 一.什么是分支结构嵌套 在一个if语句中又包含了另外一个if语句&#xff0c;这种情况称之为if语句的嵌套&#xff0c;也叫做分支结构嵌套。 二.什么情况下会用分支结构嵌套 如…

dToF直方图之美_激光雷达多目标检测

直方图提供了一种简单有效的方法来分析信号分布并识别与目标存在相对应的峰值,并且能够可视化大量数据,让测距数形结合。在车载激光雷达中,对于多目标检测,多峰算法统计等,有着区别于摄像头以及其他雷达方案的天然优势。 如下图,当中有着清晰可见的三个峰值,我们可以非…

炸弹人游戏

代码实现 广度优先搜素 深度优先搜索

巧用RTL原语实现MUX门级映射

对于前端设计人员&#xff0c;经常会需要一个MUX来对工作模式&#xff0c;数据路径进行明确&#xff08;explicit&#xff09;的声明&#xff0c;这个对于中后端工程师下约束也很重要。这里介绍一种巧用的RTL原语&#xff0c;实现MUX的方法。闲言少叙&#xff0c;ICerGo&#x…

2023自动化测试框架大对比:哪个更胜一筹?

所谓工欲善其事&#xff0c;必先利其器&#xff0c;在进行自动化测试时&#xff0c;选择一个合适的框架是至关重要的。因为一个好的测试框架可以大大提高测试效率&#xff0c;减少我们很多工作量。在选择框架之前&#xff0c;我们通常需要对不同的框架进行对比&#xff0c;以便…

Python特征工程神器:Feature Engine库详解与实战

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 特征工程是机器学习中至关重要的一环&#xff0c;而Feature Engine库作为Python中的强大特征工程工具&#xff0c;提供了丰富的功能和灵活的操作。本文将深入探讨Feature Engine的各种特性&#xff0c;包括缺失值…

Trace 在多线程异步体系下传递

JAVA 线程异步常见的实现方式有&#xff1a; new ThreadExecutorService 当然还有其他的&#xff0c;比如fork-join&#xff0c;这些下文会有提及&#xff0c;下面主要针对这两种场景结合 DDTrace 和 Springboot 下进行实践。 引入 DDTrace sdk <properties><java.…

正确看待鸿蒙不兼容Android,这不是趋势?

华为可能明年推出不兼容安卓的鸿蒙版本。11月20日&#xff0c;据澎湃新闻报道&#xff0c;一华为相关人士表示&#xff0c;推出时间还不确定&#xff0c;未来IOS、鸿蒙、安卓将为三个各自独立的系统。 稍早前据证券时报报道&#xff0c;有业内人士亦表示&#xff1a;“华为内部…

eNSP小实验(vlan和单臂路由)

一.vlan的划分 实验目的&#xff1a; ①pc1 只可以和pc2通信&#xff0c;不可以和pc3 pc4通信 ②pc1和pc2只能到Server1&#xff0c;pc3和pc4到Server2 1.拓扑图 2.配置 PC1-4 同理配置 SW1 <Huawei> <Huawei>u t m //关闭注释 Info: …

三、Shell 环境

一、Linux 系统分类 在 Linux 中&#xff0c;常见的 Shell 有以下几种&#xff1a; Bourne Shell&#xff08;sh&#xff09;&#xff1a;最早的 Shell&#xff0c;由 Stephen Bourne 开发。它是大多数其他 Shell 的基础。Bourne Again Shell&#xff08;bash&#xff09;&am…