《算法笔记》总结No.6——贪心

一.简单贪心

        贪心法是求解一类最优化问题的方法,它总是考虑在当前状态下局部最优(或较优)之后,来使全局的结果达到最优(或较优)的策略。显然,如果采取较优而非最优的策略(最优策略可能不存在或是不易想到),得到的全局结果也无法是最优的。而要获得最优结果,则要求中间的每步策略都是最优的,因此严谨使用贪心法来求解最优化问题需要对采取的策略进行证明。证明的一般思路是使用反证法及数学归纳法,即假设策略不能导致最优解,然后通过一系列推导来得到矛盾,以此证明策略是最优的,最后用数学归纳法保证全局最优。不过对平常使用来说,也许没有时间或不太容易对想到的策略进行严谨的证明(贪心的证明往往比贪本身更难),因此一般来说,如果在想到某个似乎可行的策略之后,并且自己无法举出反例,那么就勇敢地实现它。

1.组个最小数

给定数字0~9各若干个,可以任意顺序排列这些数字,但必须全部使用,且使目标数字尽可能小(当然0不能做首位)比如输入两个0、两个1、三个5和一个8,得到的最小数字就是100155858。


相信大家一下子就可以看出来策略:先从1~9中选择不为0的最小数输出,然后从0~9输出数字,每个数字输出次数为其剩余个数。

策略正确的证明

  • 首先由于所有数字都必须参与组合,因此最后结果的位数是确定的。 
  • 由于最高位不为0,则选一个尽可能小的数作为首位——最高位定理
  • 其余位数也应该从小到大输出~

教材上的实在是太抽象了,好像有点错误,这里博主自己写了一种:

#include <cstdio>
#include <vector>
#include <iostream> 
#include <algorithm>
using namespace std;int main() {	vector<int> V;for(int i=1;i<=10;i++){int temp=0;cin>>temp;V.push_back(temp);}sort(V.begin(),V.end());  //直接排成升序 int flag=0;  //标记 for(int i=0;i<=9;i++)if(V[i]!=0){int temp=V[i];V[i]=V[0];V[0]=temp;flag=i;//保存第一个不为0的位置 break;	}for(int i=flag+1;i<=9;i++)  //找更小的头,直接从flag下一位开始即可,节省时间~ if(V[i]<V[0]&&V[i]!=0){int temp=V[i];V[i]=V[0];V[0]=temp;}for(int i=0;i<=9;i++)cout<<V[i];
}

逻辑上没什么难度,主要是要想清楚~

2.月饼库存

  • 输入:第一行输入N和M:N位月饼的种类数目,M位市场对月饼的需求总量;接下来的两行均要输入N个数:第一行的N个数分别对应当前种类的月饼全部卖出后可以挣多少,而第二行的N个数对应当前月饼的总数量~
  • 要求输出:在规定需求量下最高收入

        试想一下你如果作为老板,会怎么去“贪得无厌”?很明显——只需要在有限的需求量中,尽可能多的卖出单价最贵的月饼,岂不是可以收货最多的营业额?如下博主自己写的一种实现,和教材上的也不太一样:

#include <cstdio>
#include <vector>
#include <iostream> 
#include <algorithm>
using namespace std;struct mooncake{double num;  //总数 double income;  //总收入 double price;   //单价,需要自己计算 
}; int main() {int N,M;cin>>N>>M;vector<mooncake> V;for(int i=1;i<=N;i++) {mooncake temp;V.push_back(temp);}cout<<"请输入数量:"<<endl;for(int i=1;i<=N;i++) {double num=0;cin>>num;V[i-1].num=num;}cout<<"请输入总价:"<<endl;for(int i=1;i<=N;i++) {double income=0;cin>>income;V[i-1].income=income;}for(int i=0;i<=N-1;i++) V[i].price=V[i].income/V[i].num; //计算单价//按单价降序排列!保证贵的尽可能多卖for(int i=0;i<=V.size()-1;i++){for(int j=i;j<=V.size()-1;j++)    if(V[j].price>V[i].price)    {mooncake temp;temp=V[j];V[j]=V[i];V[i]=temp;}}for(int i=0;i<=V.size()-1;i++)cout<<"单价第"<<(i+1)<<"高的值为:"<<V[i].income<<" "<<V[i].price<<" "<<V[i].num<<endl;for(int i=0;i<=N-1;i++)cout<<V[i].num<<endl; int j=0;  //使用的下标 double count=0;  //总利润 while(M>0)  //当还有需求量时 {double doubt=0;doubt=M-V[j].num; //用M减去当前类型的额总量 if(doubt>=0)//减了以后M还有剩余{M-=V[j].num;//当前种类全部卖出 count+=V[j].income;//直接总价相加 j++;cout<<V[j].num;}else if(doubt<0) //不够减这么多{count+=V[j].price*M;//剩余部分按照单价计算 break; } }cout<<"最高利润值为:"<<count<<endl;return 0;
}

        仔细品味上述中的whlie循环:当M还不为0时——即还有需求量,就卖最贵的月饼。按顺序一个一个卖:如果当前需求量足以卖完当前种类的全部数量,则直接累加总价;如果不足以卖完当前的全部,则有多少卖多少,按照单价计算即可~ 

我们拿教材的测试用例测试一下:

  • 3 20
  • 18 15 10
  • 75 72 45

结果为94.50,和标准答案一致~ 

此外这里博主直接把排序写在main函数了,写在独立的函数再调用,对于结构体型的vector好像有点bug,排序不太成功,大家如果知道原因的话可以在评论区写出来~

二.区间贪心

题干如下:

对于这类题目,只需要牢记——优先选择左端点大的区间

 

下面来说说为什么要这样做,如上图:不难发现,为了保证尽可能多选,当某个较长的区间包含了较短的区间,我们肯定要先选择最短的区间,这一点很好理解。

        而对于上面这种情况,比如1和2这种重叠的区间,不难发现,如果选了左端点最大的1区间,只会占到9号位,而选了2号区间则会占到8号位——这显然不符合贪心尽可能少花钱(少花区间)的思想,因此要选得尽可能靠左,这样右边空的会更多~如上,我们手算可以看出来最多有4个不相交的。 

教材上的代码: 

#include <cstdio>
#include <algorithm>
using namespace std;const int maxn=110;
struct Inteval{int x,y;  //开区间左右端点 
}I[maxn]; bool cmp(Inteval a,Inteval b)
{if(a.x!=b.x)return a.x>b.x;   //左端点从大到小排序 elsereturn a.y<b.y;   //左端点相同的按右端点从小到大排序 
}int main() {int n;while(scanf("%d",&n,n!=0)){for(int i=0;i<n;i++)scanf("%d%d",&I[i].x,&I[i].y);sort(I,I+n,cmp); //排序区间 int ans=1,lastX=I[0].x;//ans记录总数,lastX记录上一个被选择的区间的左端点 for(int i=1;i<n;i++){if(I[i].y<=lastX)   //如果该区间右端点在lastX左边 {lastX=I[i].x;  //以I[i]作为新选中的区间 ans++;   //不相交的区间个数+1 }	}printf("%d\n",ans);	} return 0;
}

不过博主还是不太喜欢原始数组,下面给一种vector结构体版本:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;struct section{int x=0;int y=0;//x和y分别为左右端点 
}; int main() {int n=0;vector<section> V;cin>>n;for(int i=1;i<=n;i++) //读入数据 {section temp;int x=0,y=0;cin>>x>>y;if(x>y)   //防止左端点大于右端点 {int temp1=x;x=y;y=temp1;	}else if(x==y) //若左右端点相同 {i-=1;  //则当前输入 不算cout<<"不可以输入相同的左右端点!"<<endl; continue;  //舍弃数据,本次循环作废~ }	temp.x=x;temp.y=y;V.push_back(temp);}//按要求排序区间优先级 for(int i=0;i<=V.size()-1;i++){for(int j=i+1;j<=V.size()-1;j++){if(V[j].x>V[i].x)  //左端点越大越靠前{section temp=V[j];V[j]=V[i];V[i]=temp;}else if(V[j].x==V[i].x&&V[j].y<V[i].y) //左端点相同的话,右端点小的优先 {section temp=V[j];V[j]=V[i];V[i]=temp;} }}cout<<"顺序如下:"<<endl; for(int i=0;i<=V.size()-1;i++)cout<<V[i].x<<"~"<<V[i].y<<endl; int count=1,lastX=V[0].x;//count用来统计总数,lastX是上一个符合条件的区间的左端点for(int i=1;i<=V.size()-1;i++)//直接从第二个区间开始 {if(V[i].y<lastX)  //如果当前区间的右端点不和上一个左端点相加,满足题意 {lastX=V[i].x;count++;}		} cout<<count<<endl;return 0;
}

测试如下:

 


        总的来说,贪心法是用来解决一类最优化问题,并希望由局部最优策略来推得全局最优结果的算法思想。贪心算法适用的问题一定满足最优子结构的性质,即一个问题的最优解可以由他的子问题的最优解有效地构造出来。显然不是所有问题都适合贪心法,但是这并不妨碍贪心算法成为一个简洁、实用、高效的算法~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webGL可用的14种3D文件格式,但要具体问题具体分析。

hello&#xff0c;我威斯数据&#xff0c;你在网上看到的各种炫酷的3d交互效果&#xff0c;背后都必须有三维文件支撑&#xff0c;就好比你网页的时候&#xff0c;得有设计稿源文件一样。WebGL是一种基于OpenGL ES 2.0标准的3D图形库&#xff0c;可以在网页上实现硬件加速的3D图…

无人机之飞行规划与管理篇

无人机飞行规划与管理是确保无人机安全、高效且符合法规的运行的关键步骤。这一过程包括了对飞行任务的详细安排、航线的设定以及风险的评估和管理。下面简述这一过程的主要环节&#xff1a; 一、飞行目的和任务确定 在规划之初&#xff0c;必须明确无人机的飞行目的&#xf…

ETAS工具导入Com Arxml修改步骤

文章目录 前言Confgen之前的更改Confgen之后的修改CANCanIfComComMEcuM修改CanNmCanSMDCMCanTp生成RTE过程报错修改DEXT-诊断文件修改Extract问题总结前言 通讯协议栈开发一般通过导入DBC实现,ETAS工具本身导入DBC也是生成arxml后执行cfggen,本文介绍直接导入客户提供的arxml…

如何保证Redis缓存和数据库的数据一致性

前言 如果项目业务处于起步阶段&#xff0c;流量非常小&#xff0c;那无论是读请求还是写请求&#xff0c;直接操作数据库即可&#xff0c;这时架构模型是这样的&#xff1a; 但随着业务量的增长&#xff0c;项目业务请求量越来越大&#xff0c;这时如果每次都从数据库中读数据…

链表 OJ(一)

移除链表元素 题目连接&#xff1a; https://leetcode.cn/problems/remove-linked-list-elements/description/ 使用双指针法&#xff0c;开始时&#xff0c;一个指针指向头节点&#xff0c;另一个指针指向头节点的下一个结点&#xff0c;然后开始遍历链表删除结点。 这里要注…

【SGX系列教程】(五)enclave多线程测试,以及EPC内存测试

文章目录 一. 概述二. 原理分析2.1 多线程在Enclave中的实现流程2.2 多线程和EPC内存分配之间的冲突2.3 解决多线程和EPC内存分配冲突的策略 三. 源码分析3.1 代码结构3.2 源码3.2.1 App文件夹3.2.2 Enclave文件夹3.2.3 Makefile 3.3 总结 四.感谢支持 一. 概述 在Intel SGX环境…

HarmonyOS(43) @BuilderParam标签使用指南

BuilderParam BuilderParam使用举例定义模板定义具体实现BuilderParam初始化 demo源码参考资料 BuilderParam 该标签有的作用有点类似于设计模式中的模板模式&#xff0c;类似于指定一个UI占位符&#xff0c;具体的实现交给具体的Builder&#xff0c;顾名思义&#xff0c;可以…

【算法】排序算法介绍 附带C#和Python实现代码

1. 冒泡排序(Bubble Sort) 2. 选择排序(Selection Sort) 3. 插入排序(Insertion Sort) 4. 归并排序(Merge Sort) 5. 快速排序(Quick Sort) 排序算法是计算机科学中的一个基础而重要的部分,用于将一组数据按照一定的顺序排列。下面介绍几种常见的排序算法,…

可控学习综述:信息检索中的方法、应用和挑战

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

YOLOv10改进 | Conv篇 | 利用YOLO-MS的MSBlock轻量化网络结构(既轻量又长点)

一、本文介绍 本文给大家带来的改进机制是利用YOLO-MS提出的一种针对于实时目标检测的MSBlock模块(其其实不能算是Conv但是其应该是一整个模块)&#xff0c;我们将其用于C2f中组合出一种新的结构&#xff0c;来替换我们网络中的模块可以达到一种轻量化的作用&#xff0c;我将其…

【Python基础】代码如何打包成exe可执行文件

本文收录于 《一起学Python趣味编程》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、安装PyInstaller三、使用PyInstaller打包四、验证打包是否成功五、总结 一、前言 本文介绍如何…

SFUZZ模糊测试平台全新升级,从标准到实践助力车企安全出海

开源网安模糊测试平台SFuzz全新升级&#xff0c;参照各国相关标准要求进行针对性建设&#xff0c;可为智能网联汽车信息安全测试提供更为强大的工具支持。SFuzz向被测系统输入大量随机数据&#xff0c;模拟各种异常情况&#xff0c;可以发现被测系统内潜在的缺陷和漏洞&#xf…

ChatGPT提问获取高质量答案的艺术PDF下载书籍推荐分享

ChatGPT高质量prompt技巧分享pdf&#xff0c; ChatGPT提问获取高质量答案的艺术pdf。本书是一本全面的指南&#xff0c;介绍了各种 Prompt 技术的理解和利用&#xff0c;用于从 ChatGPTmiki sharing中生成高质量的答案。我们将探讨如何使用不同的 Prompt 工程技术来实现不同的目…

C语言——结构体

一、定义和使用结构体 1.1概述 前面我们见过的数据类型&#xff0c;比如int,float,char等是在程序中简单的使用&#xff0c;如果我们要根据自己的需求来建立一些复杂的数据&#xff0c;就需要用到结构体。 例如&#xff0c;一个学生的学号&#xff0c;姓名&#xff0c;性别&am…

Python 利用pandas处理CSV文件(DataFrame的基础用法)

前面介绍过通过Python标准库中的CSV模块处理CSV文件&#xff1a; Python 利用CSV模块处理数据 相比CSV模块&#xff0c;pandas的功能更加强大&#xff0c;本文将简单介绍如何通过pandas来处理CSV文件。 文章目录 一、pandas简介二、用法示例2.1 读取CSV文件2.1.1 read_csv参数…

Python 视频的色彩转换

这篇教学会介绍使用OpenCV 的cvtcolor() 方法&#xff0c;将视频的色彩模型从RGB 转换为灰阶、HLS、HSV...等。 因为程式中的OpenCV 会需要使用镜头或GPU&#xff0c;所以请使用本机环境( 参考&#xff1a;使用Python 虚拟环境) 或使用Anaconda Jupyter 进行实作( 参考&#x…

火柴棒图python绘画

使用Python绘制二项分布的概率质量函数&#xff08;PMF&#xff09; 在这篇博客中&#xff0c;我们将探讨如何使用Python中的scipy库和matplotlib库来绘制二项分布的概率质量函数&#xff08;PMF&#xff09;。二项分布是统计学中常见的离散概率分布&#xff0c;描述了在固定次…

MUNIK解读ISO26262--系统架构

功能安全之系统阶段-系统架构 我们来浅析下功能安全系统阶段重要话题——“系统架构” 目录概览&#xff1a; 系统架构的作用系统架构类型系统架构层级的相关安全机制梳理 1.系统架构的作用 架构的思维包括抽象思维、分层思维、结构化思维和演化思维。通过将复杂系统分解…

OZON生活家居用品爆款新品

OZON生活家居用品爆款新品涵盖了多个方面&#xff0c;这些产品不仅满足了消费者对生活品质的追求&#xff0c;也反映了当前市场的热门趋势。以下是一些在OZON平台上备受关注的生活家居用品爆款新品&#xff1a; OZON生活家居用品爆款新品工具&#xff1a;D。DDqbt。COm/74rD T…

昇思25天学习打卡营第17天|基于MobileNetv2的垃圾分类

今天学习的内容是利用视觉图像技术&#xff0c;来实现垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 本章节主要包括8部分内容&#xff1a; 1、实验目的 1、了解熟悉垃圾分类应用…