题目链接
题目梗概
将一数列分成若干段,但每段的子数列之和不能超过M,问在此约束下,分成的段数最少是多少。
解题思路
一个朴素的想法是,让每一个子数列之和都尽可能的大,尽可能的接近阀值M。
做法是,从左到右遍历数列,记录遍历过的数列的和,当和大于阀值时,从前一位断开分段,子数列和进行清零,分段数加1,继续上述操作,直至遍历完。
这样做最优的原因是:我们考虑这样的情况,假设阀值是6,现在的数列是4 2 4 5 1
,该数列分成的最少段数记为n(4 2 4 5 1)
。
按照上述说法,我们首先分段出来的一段是[4 2]
,剩下的数列是4 5 1
,那此时我们可以确定,n(4 2 4 5 1) = 1 + n(4 5 1)
。
而如果我们不采取上述做法,从2之前就分段。即分出来的一段是[4]
,剩下的数列是2 4 5 1
,那这种情况下,可以确定n(4 2 4 5 1) = 1 + n(2 4 5 1)
。
很明显,n(4 5 1) <= n(2 4 5 1)
,所以前者方法最优。
完整代码
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n,m;
cin >> n >> m;
vector<int> a(n);
for(int i = 0;i<n;i++) cin >> a[i];
int ans = 0,sum = 0;
for(int i = 0;i<n;i++){
if(sum + a[i] > m){
sum = 0;
++ans;
}
sum += a[i];
}
if(sum) ++ans;
cout << ans;
return 0;
}