每日一题 —— [NOIP 2007 普及组] 纪念品分组
OK呀,也是更新这个系列了,好吧那我们话不多说,也不多说废话了,上题目
题目
时间限制
1.00s
题目描述
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入格式
共 n+2 行:
第一行包括一个整数 w,为每组纪念品价格之和的上限。
第二行为一个整数 n,表示购来的纪念品的总件数 G。
第 3∼n+2 行每行包含一个正整数 Pi 表示所对应纪念品的价格。
输出格式
一个整数,即最少的分组数目。
输入输出样例
输入
100 9 90 20 20 30 50 60 70 80 90
输出
6
说明/提示
50% 的数据满足:1≤n≤15。
100% 的数据满足:,80≤w≤200,5≤Pi≤w。
读完题目第一眼就觉得 so hard 但仔细一看这不就是一道经典的双指针题目吧,废话不多说,上思路
思路
1.看数据范围
如果使用双重循环时间复杂为
即为
。而时间限制为1.00s。所以使用暴力枚举并不能AC这道题。所以我们要另辟蹊跷。
2.深入探究
不难从题目看出我们在保证不超过W的前提下(不能买帕拉玛莱)给这N个纪念品分组。(原话:每组纪念品的价格之和不能超过一个给定的整数。乐乐希望分组的数目最少。)
所以我可以先排序,得到一个有序数组,后分别从第一个与最后一个开始找。然后进行分组。
接下来是代码部分
代码
1.完整代码
#include<bits/stdc++.h>
using namespace std;
int n,w,p[30005],ans;
int main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>w>>n;for(int i=1;i<=n;i++)cin>>p[i];sort(p+1,p+n+1);for(int i=1,j=n;i<=j;){if(p[i]+p[j]<=w){ans++;i++;j--;}else{j--;ans++;}}cout<<ans;return 0;
}接下来是代码逐步分析
2.逐步分析(敲黑板)
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 关闭与C语言与C++语言的的交互,提升cin与cout的速度(为了避免超时)
小知识
在使用上述代码时你将无法使用下述的代码
1.sacnf
2.printf
3.endl 注:endl也属于C语言转C++。可以使用“\n”代替。
接下来进行排序
sort(p+1,p+n+1);
核心部分来了
for(int i=1,j=n;i<=j;)//双指针基础模版{if(p[i]+p[j]<=w)//如果头尾两件小于或等于规定质量,那就各往中间前进一步。//可能会用小伙伴疑惑为什么是头尾相加。//原因很简单,首先以排好序的数组为前提,//如果前两个相加,就会有可能多出来许多体重没用。//如果后两数相加,就有可能多出来许多。所以选择头尾相加。{ans++;//组数加一i++;//往中间前进一步j--;//往中间前进一步}else//又有小伙伴问“作者,作者你为什么不加判p[j]>W呢”。//哥们要审题,题目保证p数组的值小于等于W了{j--;//往中间前进一步ans++;//组数加一}}总结

