版权声明:有女朋友的老江的博客,转载请告知老江 https://blog.csdn.net/qq_42367531/article/details/84259507
【题目描述】
对于给定的一个长度为 N 的正整数数列 Ai,现要将其分成连续的若干段,并且每段和不超过 M(可以等于 M),问最少能将其分成多少段使得满足要求。
【输入格式】
第一行包含两个正整数 N,M,表示了数列 Ai 的长度与每段和的最大值;
第二行包含 NNN 个空格隔开的非负整数 Ai。
【输出格式】
输出文件仅包含一个正整数,输出最少划分的段数。
【样例输入】
5 6
4 2 4 5 1
【样例输出】
3
【数据范围与提示】
对于 20%的数据,有N≤10;
对于 40% 的数据,有N≤1000;
对于 100% 的数据,有 N≤10^5, M≤10^9,MMM 大于所有数的最大值,Ai之和不超过10^9。
思路:啊呀,这绝对是我做loj的贪心以来最简单的一道题目了,话不多说。说实在的这道题我一看到就想到了dp,(无奈挠额头的表情),后面想了一下,其实用贪心更简单,直接模拟判断就好了。
判断有两个:
1.判断a[i]的值加起来是否比m大
2.判断如果加起来比m大,ans++
3.判断最后的单独一组
是不是简单的一批,真的很简单的啦,其实我觉得就是局部最优解,就是我们要尽可能的使a[i]+起来的值与m最接近,解释完毕,就这么简单。
【代码实现一:详解版】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快读
{
char c=getchar();
int x=0,f=1;
while(c<48 || c>57)
{
if(c=='-') f=-1;
c=getchar();
}
while(c>=48 && c<=57)
{
x=x*10+c-48;
c=getchar();
}
return x*f;
}
int a[110000];
int main()
{
int n,m; n=read(); m=read();
for(int i=1;i<=n;i++) a[i]=read();
int sum=0;//sum是用来记录当前累积的数的总和
int ans=0;//ans是用来记录可以成立的组合
for(int i=1;i<=n;i++)
{
if(sum+a[i]<=m) sum+=a[i];
/*
如果当前sum+a[i]的值小于m,就是他的组合和的限值的话
就把sum更新为当前的a[i]
为什么要进行这一步呢,因为题目要求的是最少的组合
所以我们要尽量是组合和尽可能大
所以这里不能直接加,而是要累加,再判断
*/
else//如果sum+a[i]>m的话,说明我们可以把前面的消除,答案+1
{
ans++;//答案+1
sum=a[i];//把前面的清零,从当前的这个a[i]继续往下算
/*
注意很多人容易忘掉这一步,这一步不可以少
因为这一步代表的就是说我们把前面的清掉
是代表前面的成为一组,跟当前我们循环到的这个a[i]
没有半点关系
所以sum一定一定要更新为a[i]
再用当前的a[i]去组合
比如说
4 2 4 m的值为6
那么我们4+2+4跳到了else这一步
所以我们知道他们的组合不是 4 2 4
而是4 2,所以就要把最后的4留下,其他的换为ans++
*/
}
}
if(sum!=0) ans++;
/*
这一步是我重点讲解的,前面的都很好理解
这一步是什么意思呢?
就是说我们一直组合组合,发现组合到最后的那一组的时候
就是剩下的时候,电脑不会给我们自动ans++
按常理最后剩下没组合的要自己一个一组
所以这里我们就要判断
如果按照了前面的之后,i已经没有的时候
但是还有数而且比m小的时候
我们就要单独判断sum剩下的值,不是0的话说明还要自成一组,ans++
就拿样例来说吧
5 6
4 2 4 5 1
前面的4 2先判断成了一组
然后4 5的时候成了一组
这个时候sum的值为5,到i=5,a[i]=1
但是5+1=6,没有大于m,所以sum这时变成了6
但实际上这是要成为一组的
所以我们就要在这里判断剩下的sum值
剩下了,就ans++,答案加一,组合加一
*/
printf("%d\n",ans);//输出答案
return 0;
}
【代码实现二:小小的变化】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
char c=getchar();
int x=0,f=1;
while(c<48 || c>57)
{
if(c=='-') f=-1;
c=getchar();
}
while(c>=48 && c<=57)
{
x=x*10+c-48;
c=getchar();
}
return x*f;
}
int a[110000];
int main()
{
int n,m; n=read(); m=read();
for(int i=1;i<=n;i++) a[i]=read();
int sum=0;
int ans=0;
for(int i=1;i<=n;i++)
{
if(sum+a[i]<=m) sum+=a[i];
else
{
ans++;
sum=a[i];
}
}
printf("%d\n",ans+1);//代表最后的组合
return 0;
}