贪心学习心得

本文记录了一次在解决二分查找问题时遇到的贪心算法题目——P1182 数列分段。通过分析,理解如何使用贪心策略将数列分为m段,使得每段数字和的最大值最小。文章介绍了如何构造check函数,并通过逐步解释证明了贪心策略的正确性。同时,文章提到了另一道进阶贪心题P2678 跳石头,讨论了其与基础题目的相似性和挑战性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某天,我在写二分的时候遇到了一道贪心题
它光辉的名字是——P1182 数列分段

简单描述题目:给出一串数(n个),将其分为m段,求每段数字和最大值的最小值

因为我就是找的二分题 数据限制 可以得出,为了降低时间复杂度,我们可以用二分法枚举,把枚举出来的数假装当成正确答案,然后分析到底正不正确

//因为主要分析的是贪心,所以l和r的取值不做解释
	int l=maxx;//maxx 是那一串数里的最大值
	int r=sum;
	int mid;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(check(mid))//check就是分析mid是不是合法的
			l=mid+1;
		else
			r=mid-1;
	}

怎么写check函数呢?

四十五度角忧伤望天



我打开了题解,看到了一个这样的代码(~~其实这是事后我自己写的~~ ):
int check(int mid)
{
	int sum=0,t=0;
	for(int i=1;i<=n;i++)
	{
		if(sum+a[i]>mid)
		{
			sum=a[i];
			t++;
		}
		else sum+=a[i];
	}
	if(t>=m) return 1;
	else return 0;
}

看到这个的蒟蒻本弱一脸懵逼,过后开始兢兢业业的分析代码

哦~~~
这个的意思是
如果这个段落里数据和还没达到假装是答案的大小,我们就塞。
如果塞不进去,就将计数器++,就重新弄下一个段落。


尊敬的题解代码做了什么我搞懂了,但是它做这些是为了什么,我还是不懂
在经历了N长时间的纠结下,我终于简化了问题:

遇到可以加的就加一定是段落数最小的,如果这么分的段落数>=m(要求分的段落数),那就是假装的答案小了,需要l=mid+1,否则就是r=mid-1


下一步就是证明为什么 遇到可以加的就加一定是段落数最小的 了
证明完之后,我发现这是一个非常简单的问题

step1:易知,若想要满足假装是答案的mid真的是答案,如果要分段,第一段一定不在在B右边,如下图


在这里插入图片描述


step2:则第二段一定存在,且不在C左边,如下图
在这里插入图片描述

step3:以此类推可证明。

就这么证明完了,确实有一丝简单 可是我还想了很久

someone告诉我这是一道经典题,一道就可以看出精髓,然后指出了另一道进阶版贪心经典——P2678 跳石头

简单重述题意:N块石头可以移开M块,只能连着跳,问跳跃距离最小值的最大值

wow~~确实很像的亚子
于是我打开了题解

bool check(int x)//这次只看check吧
{
    int sum=0;
    int cnt=0;
    int last=0;
    while(cnt<n+1)
    {
        cnt++;
        if (a[cnt]-a[last]<x) sum++;
        else last=cnt;//熟悉的内容扑面而来,简述一下就是如果两块之间的距离小于预设答案就扔掉这块石头
    }
    return sum<=m;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值