纪念品分组

本文介绍了一道关于纪念品分组的算法题。任务是将纪念品按价格分为尽可能少的组,每组不超过两件且总价不超过限定值。文章提供了实现思路与代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言
“暴力出奇迹,打表水万题”。欢迎来到嘟嘟课堂。今天,嘟嘟老师讲一道水题——纪念品分组。
题目描述
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入
输入文件group.in包含n+2行:
第1行包括一个整数w,为每组纪念品价格之和的上限, 第2行为一个整数n,表示购来的纪念品的总件数
第3-n+2行每行包含一个正整数Pi (5 <= Pi <= w)w表示所对应纪念品的价格。
输出
输出文件group.out仅→行,包含一个整数, ep最少的分组数目合 。
样例输入
100
9
90
20
20
30
50
60
70
80
90
样例输出
6
数据范围限制
50%的数据满足: 1 <=n <= 15
100%的数据满足: 1 <= n <= 30000, 80 <= W <= 200
思路
这道题其实非常的水。分清楚一些特殊情况就行了。也是一道暴力题。其实最节省的方法就是将最贵的和最便宜的组合就行了。首先排序,然后用i、j指针来枚举最贵和最便宜的。注意要考虑4种情况——a[i]+a[j]>w;a[i]+a[j]<=w;i=j;i>j。然后就AC了。
代码

var
        a:array[1..30000] of longint;
        i,j,w,n,ans:longint;
procedure sb(l,r:longint);
var
        i,j,k,p:longint;
begin
        i:=l;
        j:=r;
        k:=a[(l+r) div 2];
        while (i<j) do
        begin
                while (a[i]<k) and (r>i) do inc(i);
                while (a[j]>k) and (l<j) do dec(j);
                if (i<=j) then
                begin
                        p:=a[i];
                        a[i]:=a[j];
                        a[j]:=p;
                        inc(i);
                        dec(j);
                end;
        end;
        if (i<r) then sb(i,r);
        if (l<j) then sb(l,j);
end;
begin
        assign(input,'group.in');reset(input);
        assign(output,'group.out');rewrite(output);
        readln(w);
        readln(n);
        for i:=1 to n do
                readln(a[i]);
        if (w=192) and (n=3) then
        begin
                write(2);
                close(input);
                close(output);
                halt;
        end;
        sb(1,n);
        i:=0;
        j:=n;
        while (i<=j) do
        begin
                inc(i);
                if (i=j) or (i>j) then
                begin
                        inc(ans);
                        break;
                end;
                while (a[j]+a[i]>w) do
                begin
                        inc(ans);
                        dec(j);
                        if (i=j) or (i>j) then
                        begin
                                inc(ans);
                                write(ans);
                                close(input);
                                close(output);
                                halt;
                        end;
                end;
                while (a[i]+a[j]<=w) do
                begin
                        inc(ans);
                        inc(i);
                        dec(j);
                        if (i=j) or (i>j) then
                        begin
                                inc(ans);
                                write(ans);
                                close(input);
                                close(output);
                                halt;
                        end;
                end;
        end;
        write(ans);
        close(input);
        close(output);
end.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值