信息学奥赛一本通 贪心算法
【题目描述】
对于给定的一个长度为N的正整数数列A[i],现要将其分成连续的若干段,并且每段和不超过M(可以等于M),问最少能将其分成多少段使得满足要求。
【输入】
第1行包含两个正整数N,M,表示了数列A[i]的长度与每段和的最大值;
第2行包含N个空格隔开的非负整数A[i],如题目所述。
【输出】
一个正整数,输出最少划分的段数。
【输入样例】
5 6
4 2 4 5 1
【输出样例】
3
【提示】
【数据范围】
对于20%的数据,有N≤10;
对于40%的数据,有N≤1000;
对于100%的数据,有N≤100000,M≤,M大于所有数的最小值,A[i]之和不超过。
【分析】
注意题目描述中“分成连续的若干段”,连续的段表示队列不需要排序,按照输入的顺利来进行。要想段落数量最少,则每段近可能最大。采用贪心策略,先取一个数,将它与下一个数相加,如果和小于M,则再去取一个数添加到和里与M比较……,如果和大于等于M,则另起一段。
//从前向后,先取一个数,判断这个数与下一个数的和,如果和大于m,这个数单独一个组
while(a.size()){
int t = a.front();
ans++;
a.pop();
while(t + a.front()<= m && a.size()>0)
{
t += a.front();//将下一个数纳入到和里
a.pop();
}
}
【完整代码】
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char *argv[]) {
//队列
queue<int>a;
int n,m;
cin >> n >> m;
for(int i = 0; i < n; i++){
int t;
cin >> t;
a.push(t);
}
int ans = 0;
//从前向后,先取一个数,判断这个数与下一个数的和,如果和大于m,这个数单独一个组
while(a.size()){
int t = a.front();
ans++;
a.pop();
while(t + a.front()<= m && a.size()>0)
{
t += a.front();//将下一个数纳入到和里
a.pop();
}
}
cout << ans;
return 0;
}