题目描述
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入描述:
第 1 行包括一个整数 w,为每组纪念品价格之和的上限。
第 2 行为一个整数n,表示购来的纪念品的总件数。
第 3 ~ n+2 行每行包含一个正整数 ,表示所对应纪念品的价格。
输出描述:
包含一个整数,即最少的分组数目。
示例1
输入
100
9
90
20
20
30
50
60
70
80
90
输出
6
备注:
50%的数据满足:
100%的数据满足:
解答
把纪念品的价格按照从低到高排列,然后用两个指针(其实是两个 int 型的变量,用来表示下标),每次选择当前价格最高与价格最低的最为一组,若符号条件,则左边的指针向右移动 1,右边的指针向左移动 1;如果不行就让价格最高的单独分一组,而价格最低再和价格次高作为一组进行判断。
这样贪心下来就能使分的组数最少。
例如价格最低的是 Min,价格最高的是 Max,若 Max + Min 是大于给定的数 w,则说明不能分成一组,若这个时候 Max 再去加其他的价格,只会使得结果更大,则肯定大于 w,所以就不能分成一组。所以这个时候 Max 要自己分一组。
具体步骤:
1.定义数组,用来存储纪念品的价格:
这样贪心下来就能使分的组数最少。
例如价格最低的是 Min,价格最高的是 Max,若 Max + Min 是大于给定的数 w,则说明不能分成一组,若这个时候 Max 再去加其他的价格,只会使得结果更大,则肯定大于 w,所以就不能分成一组。所以这个时候 Max 要自己分一组。
具体步骤:
1.定义数组,用来存储纪念品的价格:
const int N = 3e4 + 10; int a[N]; // 用来存储纪念品的价格2.定义 2 个变量 w 和 n,并输入 w 和 n:
int w; // 每组纪念品价格之和的上限 int n; // 纪念品的个数 cin >> w >> n;3.输入 n 个纪念品的价格:
for (int i = 1; i <= n; i++) { // 输入 n 个纪念品的价格 cin >> a[i]; }4.用 sort 给数组 a (纪念品的价格)升序排序:
sort(a + 1, a + n + 1); // 将纪念品的价格升序排序(按照价格从低到高进行排列)5.定义 3 个变量:
int l = 1; // 左边的指针(其实是表示下标的) int r = n; // 右边的指针(其实是表示下标的) int cnt = 0; // 计数器,用来记录组数
6.当左边的指针小于等于右边的指针时,做以下操作:
(1)若两个指针指向的纪念品价格能组成一组,则左边的指针向右移动 1,右边的指针向左移动 1,组数加 1。
if (a[l] + a[r] <= w) { // 若两者之和小于等于 w,可以分成一组 l++; // 左边的指针(下标)加 1 r--; // 右边的指针(下标)减 1 cnt++; // 计数器加 1,a[l] 和 a[r] 作为一组,组数加 1 }(2)若两个指针指向的纪念品价格不能组成一组,右边的指针指向的纪念品自己是一组,组数加 1,且将右边的指针向左移动 1 (左边的指针不动,等待下一次分组)。
else { // 若不能分成一组 r--; // // 右边的指针(下标)减 1 (左边的指针不变) cnt++; // 计数器加 1,a[r] 自己作为一组 }7.输出结果:
cout << cnt; // 输出计数器,即为最少的组数
思考:
1.如何证明这样的贪心方案能得到最优解呢?
2.这里的指针是指什么?怎样使用这样的指针?你会使用了麽?
完整代码:
#include <bits/stdc++.h> using namespace std; const int N = 3e4 + 10; int a[N]; // 用来存储纪念品的价格 int main() { int w; // 每组纪念品价格之和的上限。 int n; // 纪念品的个数 cin >> w >> n; for (int i = 1; i <= n; i++) { // 输入 n 个纪念品的价格 cin >> a[i]; } sort(a + 1, a + n + 1); // 将纪念品的价格升序排序(按照价格从低到高进行排列) int l = 1; // 左边的指针(其实是表示下标的) int r = n; // 右边的指针(其实是表示下标的) int cnt = 0; // 计数器,用来记录组数 while (l <= r) { // 当左边的指针小于等于右边的指针时,记得要有等号 if (a[l] + a[r] <= w) { // 若两者之和小于等于 w,可以分成一组 l++; // 左边的指针(下标)加 1 r--; // 右边的指针(下标)减 1 cnt++; // 计数器加 1,a[l] 和 a[r] 作为一组,组数加 1 } else { // 若不能分成一组 r--; // // 右边的指针(下标)减 1 (左边的指针不变) cnt++; // 计数器加 1,a[r] 自己作为一组 } } cout << cnt; // 输出计数器,即为最少的组数 return 0; }
来源:小韦同学