【算法篇】贪心算法

目录

贪心算法

贪心算法实际应用 

一,零钱找回问题

二,活动选择问题

三,分数背包问题

将数组和减半的最小操作次数

最大数


贪心算法

贪心算法,是一种在每一步选择中都采取当前状态下的最优策略,期望得到全局最优解的算法策略。也就是说,通过局部最优解,期望得到全局最优解。

贪心算法一般按如下步骤执行:

1,问题分解: 将原问题转化为一系列子问题。

2,贪心选择:对每个子问题求解的时候,都选择当前看起来“最优的”解法。

3,合并解:累计局部最优解形成全局解。

4,正确性证明:通过数学归纳或者替换论证验证。(因为贪心策略可能是错误的)

先简单理解一下贪心算法:

例一:找零问题

这个问题在我们日常生活中很普遍。

假设我们现在可以找的零钱面额为【20,10,5,1】,并且每个有无限张。当我们想找k的零钱时,怎样可以让钱的张数最少?

这里假设k=46,用 贪心算法的思想,每一步尽可能使用面值最大的纸币即可。

46->  选一张20  -> 26  -> 选一张20 -> 6-> 选一张5->1->选一张1

例二:最小路径和

给你一个矩阵,求解:从矩阵的左上角出发,只能向下和向右两个方向走,求到达矩阵的右下角过程中,路径上所有元素和的最小值。

贪心算法实际应用 

一,零钱找回问题

假设1元,5元,10元,20元,50元,100元的纸币分别有

c0,c1,c2,c3,c4,c5张 。现在用这些钱来找回k元,求最少使用的张数。

用贪心算法的思想,每一步找钱尽可能使用面值大的。

//单张钱的面额
int signle_money[7] = { 1,2,5,10,20,50,100 };
//对应前的个数
int number_money[7] = {2,5,1,3,4,0,4};

//存放结果
int total[7] = { 0 };

int tanxin(int money)
{
    if (money >= 0)
    {
        //每一步尽量选最大的面额
        for (int i = 6; i >=0; i--)
        {
            total[i] = min(number_money[i], money / signle_money[i]);
            money = money - total[i] * signle_money[i];
        }
        return 0;
    }
    else
    {
        return money;
    }
}
int main()
{
    int k = 0;
    cout << "输入 要找回的零钱" << endl;
    cin >> k;

    if (!tanxin(k))
    {
        cout << "贪心结果为:" << endl;
        for (int i = 0; i < 7; i++)
            cout << signle_money[i] << "元:" << total[i] << "张" << endl;
    }
    else
    {
        cout << "ops wrong number" << endl;
    }
    return 0;
}
 

  

二,活动选择问题

有n个活动,a1,a2,a3...an,这些活动需要在同一天使用同一个教室。每个活动都有一个开始时间si和结束时间fi,一旦被选择后,活动ai就占据半开时间[si,fi)。如果[si,fi)和[sj,fj)互不重叠,那么ai和aj两个活动可以被安排在同一天。该问题是安排这些活动,使尽量多的活动不冲突的举行。

贪心策略:想要使尽量多的活动不冲突,那我们在选择活动时,就尽量选择结束早的活动,为后续留出更多的时间。

//活动安排问题
#include <algorithm>
struct ACT
{
    int start;
    int end;
}activity[100];

//活动的个数
int N;

bool cmp(ACT a, ACT b)
{
    return a.end < b.end;
}

int greedy()
{
    int num = 0;

    for (int i = 0, j = i + 1; i < N; j++)
    {
        if (activity[j].start > activity[i].end)
        {
            i = j;
            num++;
        }
    }

    return num;
}

int main()
{
    cout << "活动的总数:";
    cin >> N;
    cout << "输入每个活动的开始和结束:" << endl;

    for (int i = 0; i < N; i++)
    {
        cin >> activity[i].start;
        cin >> activity[i].end;
    }
    
    //将活动按结束时间排序,升序
    sort(activity, activity + N, cmp);

    //统计结果
    int res = greedy();
    cout << "安排的活动个数:" << res << endl;
    return 0;
}
 

三,分数背包问题

情景描述:给定背包容量和一些物品,每个物品有重量和价值两个属性。允许只取一个物品的一部分加入背包,求问如何才能使背包装的物品价值最大。

与01背包不同,分数背包问题允许将物品的部分装入背包。这意味着我们可以将一个物品分割成任意大小,并根据其重量比例来计算其价值。

贪心策略:

核心思想:按性价比来排序。即每个物品的单位价值:价值/重量。

按照单位价值从高到低对物品进行排序,然后依次考虑每个物品 。

算法步骤:

   1,将所有物品按照单位价值从高到低排序。

    2,遍历排序后的物品。对于每个物品:

  • 如果物品重量小于等于背包剩余容量 ,就将物品装入背包。
  • 如果物品重量大于背包剩余容量,只装入能狗适应当前容量的部分。

//分数背包问题
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Item
{
public:
    int _w;
    int _v;
    Item() = default;
    Item(int w,int v)
        :_w(w)
        ,_v(v)
    {}
};

bool cmp(Item a, Item b)
{
    return a._v / a._w > b._v /a._w;
}

double greed(vector<int>& w, vector<int>& v, int cap)
{
    vector<Item> items(w.size());
    double res = 0;

    for (int i = 0; i < w.size(); i++)
    {
        items[i] = { w[i], v[i] };
    }

    sort(items.begin(), items.end(), cmp);

    for (auto& item : items)
    {
        if (item._w <= cap)
        {
            res += item._v;
            cap -= item._w;
        }
        else
        {
            res += (double)item._v / item._w * cap;
            break;
        }
    }

    return res;
}
int main()
{
    vector<int> w = { 10,20,30,40,50 };
    vector<int> v = { 50,120,150,210,240 };
    //背包容量
    int cap = 50;
    cout << "MAX_value:" << greed(w, v, cap) << endl;

    return 0;
}

                   

将数组和减半的最小操作次数

本题链接:2208. 将数组和减半的最少操作次数 - 力扣(LeetCode)

 贪心策略:每次选出数组中的最大值,对该数减半,直到使数组和减小到一半。

算法步骤:

  • 计算出数组和的一半sum
  • 每次选数组 中最大的数a进行减半,sum-=a/2,找到sum为0结束。

在每次选最大数的时候,我们可以借助优先级队列,快速找的最大值。

class Solution {
public:
    int halveArray(vector<int>& nums) {
        priority_queue<double> heap;
        double sum=0.0;
        for(int x:nums)
        {
             sum+=x;
             heap.push(x);
        }

        sum/=2.0;
        
        int count=0;
        while(sum>0)
        {
            double t=heap.top()/2.0;
            sum-=t;
            heap.pop();
            heap.push(t);
            count++;

        }
        return count;

    }
};

最大数

本题链接:179. 最大数 - 力扣(LeetCode)

贪心策略:本题可以理解为是对数组nums进行重新“排序”,而传统的排序是根据大小排的,对于本题,则是按照题目要求。

对于nums数组中的两个元素a和b, 我们无法直接确定他们的先后关系,但我们可以从结果角度来看,如果拼接结果ab要比ba好,那么a就应该放在b的前面。

class Solution {
public:
    string largestNumber(vector<int>& nums) {
        vector<string> strs;
        for(auto x:nums)
        strs.push_back(to_string(x));

        sort(strs.begin(),strs.end(),
        [](string s1,string s2)
        {
            return s1+s2>s2+s1;
        });

        string ret;
        for(auto& s:strs)
        ret+=s;
        //处理前导0
        if(ret[0]=='0') return "0";

        return ret;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5 计算机网络

5 计算机网络 5.1 OSI/RM七层模型 5.2 TCP/IP协议簇 5.2.1:常见协议基础 一、 TCP是可靠的&#xff0c;效率低的&#xff1b; 1.HTTP协议端口默认80&#xff0c;HTTPSSL之后成为HTTPS协议默认端口443。 2.对于0~1023一般是默认的公共端口不需要注册&#xff0c;1024以后的则需…

动态规划LeetCode-1035.不相交的线

在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足&#xff1a; nums1[i] nums2[j]且绘制的直线不与任何其他连线&#xff08;非水平线&#xff09;相…

禅道社区版项目管理软件部署(记录篇)

系统要求&#xff08;这里推荐使用docker容器化方式&#xff09;安装前的准备Docker快速安装最后通过查看地址验证是否部署成功开始界面化安装配置 禅道&#xff08;ZenTao&#xff09;是一款国产开源的项目管理软件&#xff0c;专注于敏捷开发流程&#xff0c;支持 Scrum 和 K…

数据结构-基础

1、概念&#xff1a; 程序 数据结构 算法 2、程序的好坏 可读性&#xff0c;稳定性&#xff0c;扩展性&#xff0c;时间复杂度&#xff0c;空间复杂度。 3、数据结构 是指存储、组织数据的方式&#xff0c;以便高效地进行访问和修改。通过选择适当的数据结构&#xff0c; 能…

从零开始:OpenCV 图像处理快速入门教程

文章大纲 第1章 OpenCV 概述 1.1 OpenCV的模块与功能  1.2 OpenCV的发展 1.3 OpenCV的应用 第2章 基本数据类型 2.1 cv::Vec类 2.2 cv&#xff1a;&#xff1a;Point类 2.3 cv&#xff1a;&#xff1a;Rng类 2.4 cv&#xff1a;&#xff1a;Size类 2.5 cv&#xff1a;&…

1-kafka服务端之延时操作前传--时间轮

文章目录 背景时间轮层级时间轮时间轮降级kafka中的时间轮kafka如何进行时间轮运行 背景 Kafka中存在大量的延时操作&#xff0c;比如延时生产、延时拉取和延时删除等。Kafka并没有使用JDK自带的Timer或DelayQueue来实现延时的功能&#xff0c;而是基于时间轮的概念自定义实现…

Java 注解使用教程

简介 Java 1.5 引入了注解&#xff0c;现在它在 Java EE 框架&#xff08;如 Hibernate、Jersey 和 Spring &#xff09;中被大量使用。Java 注释是该语言的一个强大特性&#xff0c;用于向 Java 代码中添加元数据。它们不直接影响程序逻辑&#xff0c;但可以由工具、库或框架…

第17章 读写锁分离设计模式(Java高并发编程详解:多线程与系统设计)

1.场景描述 对资源的访问一般包括两种类型的动作——读和写(更新、删除、增加等资源会发生变化的动作)&#xff0c;如果多个线程在某个时刻都在进行资源的读操作&#xff0c;虽然有资源的竞争&#xff0c;但是这种竞争不足以引起数据不一致的情况发生&#xff0c;那么这个时候…

强化学习 DAY1:什么是 RL、马尔科夫决策、贝尔曼方程

第一部分 RL基础&#xff1a;什么是RL与MRP、MDP 1.1 入门强化学习所需掌握的基本概念 1.1.1 什么是强化学习&#xff1a;依据策略执行动作-感知状态-得到奖励 强化学习里面的概念、公式&#xff0c;相比ML/DL特别多&#xff0c;初学者刚学RL时&#xff0c;很容易被接连不断…

【STM32系列】利用MATLAB配合ARM-DSP库设计FIR数字滤波器(保姆级教程)

ps.源码放在最后面 设计IIR数字滤波器可以看这里&#xff1a;利用MATLAB配合ARM-DSP库设计IIR数字滤波器&#xff08;保姆级教程&#xff09; 前言 本篇文章将介绍如何利用MATLAB与STM32的ARM-DSP库相结合&#xff0c;简明易懂地实现FIR低通滤波器的设计与应用。文章重点不在…

DeepSeek-R1 本地电脑部署 Windows系统 【轻松简易】

本文分享在自己的本地电脑部署 DeepSeek&#xff0c;而且轻松简易&#xff0c;快速上手。 这里借助Ollama工具&#xff0c;在Windows系统中进行大模型部署~ 1、安装Ollama 来到官网地址&#xff1a;Download Ollama on macOS 点击“Download for Windows”下载安装包&#x…

Llama最新开源大模型Llama3.1

Meta公司于2024年7月23日发布了最新的开源大模型Llama 3.1&#xff0c;这是其在大语言模型领域的重要进展。以下是关于Llama 3.1的详细介绍&#xff1a; 参数规模与训练数据 Llama 3.1拥有4050亿&#xff08;405B&#xff09;参数&#xff0c;是目前开源领域中参数规模最大的…

Linux之安装docker

一、检查版本和内核是否合格 Docker支持64位版本的CentOS 7和CentOS 8及更高版本&#xff0c;它要求Linux内核版本不低于3.10。 检查版本 cat /etc/redhat-release检查内核 uname -r二、Docker的安装 1、自动安装 Docker官方和国内daocloud都提供了一键安装的脚本&#x…

2022年全国职业院校技能大赛网络系统管理赛项模块A:网络构建(样题3)-网络部分解析-附详细代码

目录 附录1:拓扑图 附录2:地址规划表 1.SW1 2.SW2 3.SW3 4.SW4 5.SW5 6.SW6 7.SW7 8.R1 9.R2 10.R3 11.AC1 12.AC2 13.AP2 14.AP3 15.EG1 16.EG2 附录1:拓扑图 附录2:地址规划表 设备

Vim跳转文件及文件行结束符EOL

跳转文件 gf 从当前窗口打开那个文件的内容&#xff0c;操作方式&#xff1a;让光标停在文件名上&#xff0c;输入gf。 Ctrlo 从打开的文件返回之前的窗口 Ctrlwf 可以在分割的窗口打开跳转的文件&#xff0c;不过在我的实验不是次次都成功。 统一行尾格式 文本文件里存放的…

《Angular之image loading 404》

前言&#xff1a; 千锤万凿出深山&#xff0c;烈火焚烧若等闲。 正文&#xff1a; 一。问题描述 页面加载图片&#xff0c;报错404 二。问题定位 页面需要加载图片&#xff0c;本地开发写成硬编码的形式请求图片资源&#xff1a; 然而部署到服务器上报错404 三。解决方案 正确…

Windows Docker笔记-Docker容器操作

在文章《Windows Docker笔记-Docker拉取镜像》中&#xff0c;已经拉取成功了ubuntu镜像&#xff0c;本章来讲解如何通过镜像来创建容器并运行容器。 这里再类比一下&#xff0c;加深理解&#xff0c;比如&#xff0c;我们现在想开一个玩具厂&#xff0c;我们的最终目的肯定是想…

upload-labs安装与配置

前言 作者进行upload-labs靶场练习时&#xff0c;在环境上出了很多问题&#xff0c;吃了很多苦头&#xff0c;甚至改了很多配置也没有成功。 upload-labs很多操作都是旧时代的产物了&#xff0c;配置普遍都比较老&#xff0c;比如PHP版本用5.2.17&#xff08;还有中间件等&am…

(2025|ICLR,音频 LLM,蒸馏/ALLD,跨模态学习,语音质量评估,MOS)音频 LLM 可作为描述性语音质量评估器

Audio Large Language Models Can Be Descriptive Speech Quality Evaluators 目录 1. 概述 2. 研究背景与动机 3. 方法 3.1 语音质量评估数据集 3.2 ALLD 对齐策略 4. 实验结果分析 4.1 MOS 评分预测&#xff08;数值评估&#xff09; 4.2 迁移能力&#xff08;在不同…

深入理解linux中的文件(下)

目录 一、语言级缓冲区和内核级缓冲区 二、C语音中的FILE* fp fopen(“./file.txt”,"w"): 四、理解磁盘结构&#xff1a; 物理结构 逻辑结构 五、未被打开的文件&#xff1a; 六、更加深入理解inode编号怎么找到文件&#xff1a; 七、对路径结构进行…