贪心算法例题与讲解(1)
创始人
2024-05-30 23:54:30
0

文章首发于:My Blog 欢迎大佬们前来逛逛

P2240 部分背包问题

P2240 【深基12.例1】部分背包问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

有点像01背包,但是又不是,01背包的物品的是不能再分的,而本题的物品是可以再分的,因此我们可以根据某个物品的部分重量和单位价值算出它的部分最大价值来作为我们选择的物品。

  1. 首先计算单位价值 = 总价值 / 总重量

  1. 按照贪心的思想,则单位价值大的一定是越优的,因此排序,单位价值大的排在前面。

  1. 按照单位价值排好序的顺序一个一个物品选,若背包的剩余容量不够则取某个物品的部分最大价值,然后退出即可。

//TODO: Write code here
int n,T;
const int N=1e4+10;
struct Node
{double w,v,pro;
}node[N];
bool cmp(Node a,Node b)
{if (a.pro>b.pro){return true;}return false;
}
signed main()
{cin>>n>>T;for (int i=1;i<=n;i++){cin>>node[i].w>>node[i].v;node[i].pro=node[i].v/node[i].w;	//计算单位价值}sort(node+1,node+1+n,cmp);//按照单位价值排序double ans=0;double temp=T;for (int i=1;i<=n;i++){if (temp>=node[i].w){ans+=node[i].v;temp-=node[i].w;}else{ans+=(temp*node[i].pro);//取最大部分价值break;}}printf("%.2lf",ans);
#define one 1return 0;
}

P1223 排队接水

排队接水

排队接水:一列人排成一队,接水的人有个接水的时间,而其他人都要等这个人接完水,然后再轮流接水,已经接完水的就完成任务了,即不需要算在排队等接水的人当中了。

我们要计算n个人的平均接水时间,因此需要把当前人接水的时间 * 后面等待的总人数

因此我们可以总结出:最先接水的一定是接水所需时间最少的。为什么?

  • 如果你的接水时间是 1000 ,那么除这个人之外的9个人就需要等待 9 * 1000的时间。

  • 如果你的接水时间是 10 ,那么除这个人之外的9个人就需要等待 9 * 10 的时间。

很显然按照接水时间短的先接水的这种做法一定是最优的。

那么就直接按照时间排序即可,然后计算 平均的等待时间,最后再除以一次总人数。

//TODO: Write code here
int n,m;
const int N=1e6+10;
int nums[N],presum[N];
struct Node
{int num,val;
}node[N];
bool comp(Node a,Node b)
{if (a.val>n;for (int i=1;i<=n;i++){node[i].num=i;cin>>node[i].val;}sort(node+1,node+1+n,comp);// 按照接水的时间排序,如果时间相等,则按序号double ans=0;for (int i=1;i<=n;i++){ans+=(n-i)*node[i].val;//后面的每个人都需要等这个时间cout<

P1803 凌乱的yyy / 线段覆盖

P1803 凌乱的yyy / 线段覆盖

这道题其实就是贪心的经典问题:给出任务的开始和结束时间,求总共能完成的任务的最大数量

贪心思路:

  • 结束时间早的一定是最优的(在此不给出证明)

过程如下;

  1. 因此把每个任务按照结束时间排序,结束时间早的是最优的。

  1. 按照结束时间早正序排序,如果下一个任务的开始时间在上一个任务的进行过程中,则说明还没有完成上一个任务,因此跳过这个任务,只能是下一个任务的开始时间最差的等于上一个任务的结束时间

//TODO: Write code here
int n,m;
const int N=1e6+10;
int nums[N];
struct Node
{int s,e;
}node[N];
bool comp(Node a,Node b)
{if (a.e<=b.e) return true;return false;
}
signed main()
{cin>>n;for (int i=1;i<=n;i++){cin>>node[i].s>>node[i].e;}//结束时间最早int ans=0;int fg=0;sort(node+1,node+1+n,comp);for (int i=1;i<=n;i++){if (i==1)//第一个一定是可以的{ans++;fg=i;}else {if (node[i].s>=node[fg].e)	//如果下一个任务的开始在上一个任务的结束,则可以{fg=i;ans++;}}}cout<

P1090 [NOIP2004 提高组] 合并果子

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G

题目让我们求合并两堆的最小花费的总和, 因此我们很容易想到最小的两堆一起合并一定是最优的

我们便可以想到直接排序即可,花费小的在前面,然后前两个合并成一个,然后再把这个合并的放进去再排序,最后知道这个队列只有一个元素为止,因此我们每次所统计的两堆的和就是最后的答案。

这道题目的思想是很容易的。

但是如何做到 将两堆取出来合并后的值再放回去 ? 我们可以想到 堆排序。

进而想到堆排序的一个应用:优先队列

我们要制造 小顶堆,即堆顶元素是最小的,然后取出堆的前两个元素,合并后再插入堆

优先队列C++:priority_queue小顶堆形式:

priority_queue,greater> q;

大顶堆形式:

priority_queue q;

因此就解决了,当然你也可以手写堆,包含构建初始堆和堆的调整过程

//TODO: Write code here
int n,m;
const int N=1e5+10;
int nums[N];
signed main()
{cin>>n;priority_queue,greater> q;for (int i=1;i<=n;i++){int num;cin>>num;q.push(num);}if (q.size()==1)//特判{cout<=2){int num1=q.top();	//取出最小的q.pop();int num2=q.top();	//取出第二小的q.pop();int sum=num1+num2;ans+=sum;//注意统计resq.push(sum);	//合并后再插入堆}cout<

P3817 小A的糖果

P3817 小A的糖果

让我们求 在相邻的两个盒子的总数不超过 m 的情况下,至少需要吃的数量。

貌似我们可以进行排序? 从小到大,然后从左往右吃

不可以

我们注意到盒子是有先后顺序的,因此不能够改变位置(当然如果你会排序的做法则当我没说)

我们就直接贪心即可:

  1. 从左往右遍历,如果当前的盒子 i 的数量 + 后一个盒子 i+1 的数量 超过了规定 m,则我们一定需要在这两个中吃糖果,如何吃呢?

  1. 如果我们选择吃 i ,则 我们只会改变 i+1着一种情况,即 【i,i+1】是一组

  1. 但是如果我们吃 i+1,则我们不仅改变了【i,i+1】这一组,还可能改变 【 i+1,i+2】下一组,因此吃后面的一定是最优的(求最少的吃的数量)

  1. 遍历到后面的每个 i 盒子的时候,它的 i -1个位置的盒子数量 一定被上一种情况吃了。但是我们的第 1 个盒子怎么办呢,它可没有前一个?

  1. 我们直接错一下位即可, 让0(实际不存在,从1开始)号盒子 与 1 号成一组,然后我们吃后面的,这样不就吃到 1 号盒子了吗

//TODO: Write code here
int n,m;
const int N=1e5+10;
int nums[N];
signed main()
{cin>>n>>m;for (int i=1;i<=n;i++){cin>>nums[i];}int ans=0;for (int i=1;i<=n;i++){int a=i-1,b=i;	//从0开始,则保证了1号也能作为第二个盒子if (nums[a]+nums[b]>m){//尽量吃第二个ans+=nums[a]+nums[b]-m;//两个的总数 - 规定 = 这组中要吃的数量nums[b]=m-nums[a];	//全部吃第二个盒子}}cout<

P1106 删数问题

P1106 删数问题

在序列中删除 k 位后能够组成的最小的数。

貌似很简单?

直接从左往右,碰到一个 i 位置元素如果比 i-1 位置的元素大 ,则删除 i 位置的元素?

错误的!!

示例:

1 5 9 8 (2) ,删除两个,按照上面的思路,则删除 5 和 9,最后得到 18,但是实际上 15是最优的(删后两个)

1 2 6 5 9 7 (3),删除三个,按照上面的思路,则删除 2 6 和 9,得到了 1 5 7,但是实际上只要 2没被删除则其他的都比这个小。

那么怎么删呢? 观察一下式子,定义:比两边都大,则此位置为山峰

1 5 9(山峰) 8(山峰) :删除山峰,得到 1 5

为什么 8 也是山峰,9比8大啊,因为我们提前删除了9,因此 8 的前面是 5。

1 2 6(山峰) 5 9(山峰) 7(山峰):删除山峰,得到 1 2 5

答案:我们删除山峰位置的元素,则最后的数一定是最小的


实际上山峰在此题只需要表示为:比后面的数大即可

//TODO: Write code here
int n,k;
const int N=1e5+10;
char s[N];
int p=1;
bool vis[N];
signed main()
{cin>>s>>k;int len=strlen(s);//原始长度while (k--)//需要删除 k 个元素,每次循环一次则一定删除一个元素{for (int i=0;is[i+1]) //如果比后面的数字大,则删除 i 位置{//后面的位置元素依次覆盖过来,模拟删除 i 位置元素for (int j=i;j

相关内容

热门资讯

李光洁32天走7500公里吃8... 李光洁32天走7500公里吃8城,《拿一座城市下酒》这部纪录片怎么样?我觉得这部纪录片非常好,观看的...
每我世如你果只没界喜就欢的生一... 每我世如你果只没界喜就欢的生一爱有你过在想会。把这22个字组成一句话。我想过,如果在每一生只喜欢你,...
调查校园里的植物和动物说说有哪... 调查校园里的植物和动物说说有哪些动植物?可以分成几类?兰花,梅花可人丌··植物:乔木(杨树、柳树、银...
血脂高的原因? 血脂高的原因?血脂高的原因高血脂的诱因包括原发性和继发性两种:原发性高血脂症的病因:1、遗传因素。2...
为什么孩子总是重复看同一集动画... 为什么孩子总是重复看同一集动画片?是在传递这3个信号 小孩子爱看动画片是非常普遍的,动画片带给他们动...
终极三国里 49集刘备为什么这... 终极三国里 49集刘备为什么这么做?有没有官方回答?下集自己看吧 现在不会有官方回答的哟第一:可能真...
西式糕点制作大全的内容简介 西式糕点制作大全的内容简介《西式糕点制作大全》主要介绍了制作甜点的基本知识,例如各种制作工具,制作点...
逻辑思维又是什么?就是推理吗,... 逻辑思维又是什么?就是推理吗,怎么培养!?逻辑思维是一种严格分析思维。不一定是推理。推理是逻辑思维的...
囊萤夜读有一句俗语就是出自这个... 囊萤夜读有一句俗语就是出自这个故事你知道是什么吗?囊萤映雪 ( náng yíng yìng xuě...
什么是不伦恋情? 什么是不伦恋情?什么是不伦恋情.,?男跟女年龄相差很大?还是?男的比女的小?还是老夫少妻?是近亲谈恋...
有书名带晨星的嘛? 有书名带晨星的嘛?有书名带晨星的嘛?晨星传这本书。漫画书晨星物语
如果有些事情说不出口怎么办? 如果有些事情说不出口怎么办?烦恼皆是因为自己过分的执着 即使你在这样子下去 更不就不会有好的结果 为...
有哪些类似于《非自然死亡》题材... 有哪些类似于《非自然死亡》题材的日剧推荐?非自然死亡的题材电影确实不多,电视剧的话也不好找啊。不喜欢...
素书全集的内容简介 素书全集的内容简介 本书采用了《素书》的权威原著,参照《四库全书》并加上了宋代宰相张商英的注和清代王...
【世纪花园】小区对口的学校有重... 【世纪花园】小区对口的学校有重点小学和初中吗?世纪花园东区里有未来强者幼儿园,小区南边有个华兴小区,...
东南大学现有的专业中有哪些是属... 东南大学现有的专业中有哪些是属于老东南的1928年学校改名为国立中央大学,设理、工、医、农、文、法、...
一个男人一有钱就请朋友吃饭,没... 一个男人一有钱就请朋友吃饭,没钱就又说,买东西还赊账,商店里的老板都找上门来了?像陵念前这种男人的话...
坟上栽什么草好? 坟上栽什么草好?坟地种什么草好耐旱坟上栽野蕨草、扎根不深、浅根植物、可以固土、南方雨水多、不会造成坟...
关于国富潜力基金 关于国富潜力基金我9月24日上午买的国富基金,申购价格是9月24日开盘的价格吗?还是9月28日开盘的...
我是一个高中生。想学武术。在学... 我是一个高中生。想学武术。在学校没什么时间。是练散打还是跆拳道好。我是一个高中生。想学武术。在学校没...