《算法笔记》总结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.mzph.cn/web/43250.shtml

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

相关文章

【深入理解JVM】关于Object o = new Object()

1. 解释一下对象的创建过程 “半初始化”状态通常指的是对象在内存分配后、但在完全初始化之前的一种状态。在Java中&#xff0c;虽然JVM的规范和设计努力避免对象处于这种不稳定的状态&#xff0c;但在多线程环境下&#xff0c;由于指令重排序等并发问题&#xff0c;仍有可能…

【LeetCode刷题笔记】LeetCode.24.两两交换链表中的节点

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…

新手小白的pytorch学习第一弹-------张量

1 导入pytorch包 import torch2 创建张量&#xff08;tensor&#xff09; scalar标量 scalar torch.tensor(7) scalartensor(7)scalar.ndim查看scalar的维度&#xff0c;因为scalar是标量&#xff0c;所以维度为0 0scalar.shapetorch.Size([])torch.item()7vector&#xf…

Apache功能配置:访问控制、日志分割; 部署AWStats日志分析工具

目录 保持连接 访问控制 只允许指定ip访问 拒绝指定主机其他正常访问 用户授权 日志格式 日志分割 操作步骤 使用第三方工具cronolog分割日志 AWStats日志分析 操作步骤 访问AwStats分析系统 保持连接 Apache通过设置配置文件httpd-default.conf中相关的连接保持参…

基于Java的科大讯飞大模型API调用实现

写在前面&#xff1a;因为现在自己实习的公司新拓展的一个业务是结合AI的低代码平台&#xff0c;我负责后端的开发&#xff0c;之前一直都是直接使用gpt或者文心一言等ui界面来直接使用大模型&#xff0c;从来没有自己调接口过&#xff0c;所以本文记录一下自己第一次使用大模型…

【QT】QComboBox允许输入查询,且不区分大小写

目录 0.简介 1.环境 2.详细代码 3.参考 0.简介 项目需求&#xff0c;原本有一个下拉框&#xff0c;但是条目太多&#xff0c;不好搜索&#xff0c;所以用户要求可以输入查找 修改前 &#xff1a; 修改后&#xff1a; 1.环境 windows11 vs-code qt5.12 2.详细代码 QComboB…

MD5加密和注册页面的编写

MD5加密 1.导入包 npm install --save ts-md5 2.使用方式 import { Md5 } from ts-md5; //md5加密后的密码 const md5PwdMd5.hashStr("123456").toUpperCase(); 遇见的问题及用到的技术 注册页面 register.vue代码 <template><div class"wappe…

关于Python中的字典你所不知道的七个技巧

01 引言 Python是我最喜欢的编程语言之一&#xff0c;它向来以其简单性、多功能性和可读性而闻名。 字典作为Python中最常使用的数据类型&#xff0c;大家几乎每个人都或多或少在项目中使用过字典&#xff0c;但是字典里有一些潜在的技巧可能并不是每个同学都会用到。 在本文…

【UE5.1 角色练习】16-枪械射击——瞄准

目录 效果 步骤 一、瞄准时拉近摄像机位置 二、瞄准偏移 三、向指定方向射击 四、连发 效果 步骤 一、瞄准时拉近摄像机位置 打开角色蓝图&#xff0c;在事件图表中添加如下节点&#xff0c;当进入射击状态时设置目标臂长度为300&#xff0c;从而拉近视角。 但是这样切…

勇攀新高峰|暴雨信息召开2024年中述职工作会议

7月8日至9日&#xff0c;暴雨信息召开2024年中述职工作会议&#xff0c;总结回顾了上半年的成绩和不足&#xff0c;本次会议采用线上线下的方式举行&#xff0c;公司各部门管理人员、前台市场营销人员参加述职&#xff0c;公司领导班子出席会议。 本次述职采取了现场汇报点评的…

数字滚动动画~

前言 数字从0.00滚动到某个数值的动画 实现&#xff08;React版本&#xff09; Dom <div className"number" ref{numberRef}>0.00</div> JS const _initNumber () > {const targetNumber 15454547.69;const duration 1500;const numberElement…

【UML用户指南】-33-对体系结构建模-系统和模型

目录 1、系统和子系统 2、模型和视图 3、跟踪 4、常用建模技术 4.1、对系统的体系结构建模 4.2、对系统的系统建模 模型是对现实世界的简化——即对系统的抽象&#xff0c;建立模型的目的是为了更好地理解系统。 1、系统和子系统 一个系统可能被分解成一组子系统&#…

09.C2W4.Word Embeddings with Neural Networks

往期文章请点这里 目录 OverviewBasic Word RepresentationsIntegersOne-hot vectors Word EmbeddingsMeaning as vectorsWord embedding vectors Word embedding processWord Embedding MethodsBasic word embedding methodsAdvanced word embedding methods Continuous Bag-…

esp32硬件电路设计

ESP-IDF 入门指南 | 乐鑫科技 (espressif.com) ESP32-DevKitC V4 入门指南 - ESP32 - — ESP-IDF 编程指南 v5.1 文档 (espressif.com)

每日一题~abc356(对于一串连续数字 找规律)

添加链接描述 题意&#xff1a;对于给定的n,m 。计算0~n 每一个数和m & 之后&#xff0c;得到的数 的二进制中 1的个数的和。 一位一位的算。最多是60位。 我们只需要计算 在 1-n这些数上&#xff0c;有多少个数 第i位 为1. 因为是连续的自然数&#xff0c;每一位上1 的…

Linux下的misc设备驱动

文章目录 前言一、misc是什么&#xff1f;二、调用API1.注册2.注销 三、驱动框架总结 前言 misc设备即杂项设备&#xff0c;Linux系统中类似按键、触摸屏都有专门框架处理&#xff0c;类似adc、蜂鸣器等设备无法明确其属于什么类型&#xff0c;一般就归属于杂项设备&#xff0…

Sqli-labs合集之环境搭建

Sqli-labs的搭建 搭建第一个SQL注入学习靶场环境&#xff1a; 软件&#xff1a;sqli-labs 安装过程&#xff1a; 1.源码地址&#xff1a;GitHub - Audi-1/sqli-labs: SQLI labs to test error based, Blind boolean based, Time based.&#xff1b; 2.将压缩包解压到phpst…

非线性系列(三)—— 非线性求解器算法分类

1. 总体认知 CAE中的非线性方程组求解主要依赖牛顿法&#xff08;及牛顿法的变体&#xff09;&#xff0c;步骤如下 以线搜索方法为例&#xff0c;流程如下: 2. 方法分类 适用范围大类小类描述牛顿法雅可比矩阵难获取拟牛顿法 Broyden&#xff08;Secant method&#xff09;、…

15. Revit API: Transaction(事务)与 Failures(故障处理)

前言 UI讲完&#xff0c;回到DB这块儿。在Document那篇&#xff0c;提到增删改查操作都是在Document上&#xff0c;是对Documet进行操作。 看到“增删改查”这四个&#xff0c;想到什么了没有&#xff1f; 数据库&#xff08;DB&#xff09;嘛~话说那本经典的红皮数据库的书叫…

网络安全----防御----防火墙安全策略组网

防火墙组网 要求&#xff1a; 1&#xff0c;DMz区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问。 2&#xff0c;生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3&#xff0c;办公区设备10.0.…