【NOIP2007普及组】纪念品分组
【NOIP2007普及组】纪念品分组
【输入格式】
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
【输入格式】
输入包含n+2行:
第1行包括一个整数w,为每组纪念品价格之和的上限,第2行为一个整数n,表示购来的纪念品的总件数G。
第3-n+2行每行包含一个正整数Pi(5<=Pi<=w3)w表示所对应纪念品的价格。
【输出格式】
输出仅一行,包含一个整数,即最少的分组数目。
【输入样例1】 【输出样例1】
100 6
9
90
20
20
30
50
60
70
80
90
【提示】
50%的数据满足: 1 <=n <= 15
100%的数据满足: 1 <= n <= 30000, 80 <= W <= 200
【题解】
这题很显而易见地可以使用贪心算法来解。
考虑最便宜的纪念品i,它应该跟哪个纪念品同组?如果其它的每个纪念品都不能和它一起同组,那么只能每个纪念品单独一组,但如果有可以跟它一起同组的纪念品,那纪念品i就应该选择能和它同组的纪念品中最重的一个纪念品j。这样的分组可以让分的组尽可能的少。这是一个贪心策略。
所以得出贪心策略:最便宜的纪念品和最贵的纪念品分组。
很显然,这个贪心策略的正确性和有效性可以通过反证法证明。证明如下:
假设这个贪心策略不是最优解,那最优方案中的纪念品i应该如何?
情况1:i不和任何纪念品分组。如此的话可以把j加进来分到同一组,分组数不会增加(甚至还有可能减少)。符合贪心策略。
情况2:i和另一个纪念品k同组,其中k比j便宜。把k和j交换后,原来的分组仍不会超过价格上限(显而易见的事实:k比j便宜)。因此i和j同组,所得新解不会更差。符合贪心策略。
由此可见:这样的贪心策略不会丢失最优解。
附上代码:
【实现代码】
#include <bits/stdc++.h> using namespace std; int n,w; int ans=0; int num[35010]={0}; int cheap=1,dear; int main() { cin>>w>>n; dear=n; for(int i=1;i<=n;i++) cin>>num[i]; sort(num+1,num+n+1); //对纪念品的价格进行从小到大快排。 while(cheap<=dear) if(num[cheap]+num[dear]>w) ans++,dear--; else cheap++,dear--,ans++; cout<<ans<<endl; return 0; }
【代码解释】
在前面的分析中,比j还贵的纪念品只能单独一个组。故我们只需两个指针cheap和dear,分别表示最便宜的和最贵的纪念品(排序后)。若两个纪念品不能同组,就将dear的纪念品单独一组。若可以则继续分组(cheap++,dear--;)。直到每个纪念品都可以分组。
2020-03-29 17:01:36

浙公网安备 33010602011771号