聪明人的游戏 信息学探秘 提高篇 第六章 贪心算法(C++) 第2课 纪念品分组(group)

文章介绍了如何使用C++编程解决纪念品分组问题,目标是最小化分组数。提供了两种方法,一种基于桶排序,另一种利用快速排序,以确保纪念品价格不超过给定上限且每组最多两件纪念品。通过对输入纪念品价格的排序和匹配,找到最佳组合策略。
摘要由CSDN通过智能技术生成

【题目描述】

    元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。

你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

【输入格式】

    包含n+2行:

    第1行包括一个整数w,为每组纪念品价格之和的上限;第2行为一个整n,表示购来的纪念品的总件数;

    第3到n+2行每行包含一个正整数Pi(5≤Pi≤w),表示所对应纪念品的价格。

【输出格式】

    仅一行,包含一个整数,表示最少的分组数目。

【输入样例】

   100

    9

    90

    20

    20

    30

    50

    60

    70

    80

    90

【输出样例】

    6

【数据范围】

    50%的数据满足:1≤n≤15;

    100%的数据满足:1≤n≤30000,80≤w≤200。




C++ 方法一:

#include <bits/stdc++.h>
using namespace std;
int a[30010],b[30010],c[30010];
int ans=0;
int main( void )
{
	int w,n;

	//第 1 行包括一个整数 w,为每组纪念品价格之和的上限;
	//第 2 行为一个整数 n,表示购来的纪念品的总件数;
	cin>>w>>n;
	
	for(int i=1;i<=n;++i)
	{
		//第 3 到 n+2 行每行包含一个正整数 Pi(5≤Pi≤w),
		//表示所对应纪念品的价格。
		cin>>a[i];
		
		//桶排序 预处理 
		++b[ a[i] ];
	}
	
	/*
	for(int i=1;i<=300;++i)
	{
		while( b[i]--)
		{
			cout<<i<<" ";
			cout<<b[i]<<endl;
		}
	}
	cout<<endl;
	*/
	
	
	
	int m=0;
	
	for(int i=1;i<=n;++i)
	{
		if( b[a[i]] )//b[20]=2 
		{
			--b[ a[i] ];//20
			int j=w-a[i];//80
			//w=j+a[i];
			
			//找不到则什么都不做 
			for(;j>0 && b[j] == 0; --j)
			{
				;
			}
			
			//c[j]==0 表示没有用过 
			if( b[j] && c[j]==0 )
			{
				--b[j];
				
				//用过不能再用 
				c[j]=1;	
			}
			
			++ans;
			
			
			cout<<"i="<<i<<" b["<<a[i]<<"]="<<b[a[i]]<<" ans="<<ans<<endl;
		}
	}
	
	cout<<ans<<endl;
}
/*
【输入样例】
    100
    9
    90
    20
    20
    30
    50
    60
    70
    80
    90
【输出样例】
    6
*/

C++方法二:

#include <bits/stdc++.h>
#include <algorithm>  //algorithm:算法 
using namespace std;
int price[30005];
int main()
{
	int w,n;
	
	//第1行包括一个整数w,为每组纪念品价格之和的上限;
	cin>>w;
	
	//第2行为一个整数n,表示购来的纪念品的总件数;
	cin>>n;
	
	//第3到n+2行每行包含一个正整数Pi(5≤Pi≤w),
	//表示所对应纪念品的价格。
	for(int i=1;i<=n;++i)
	{
		cin>>price[i]; //price
	}
	
	//快速排序是一种比桶排序、
	//冒泡排序、选择排序更好的一种排序算法。 
	sort(price+1,price+n+1);  //price[1]-prince[n];
	
	int i=1,j=n;
	int ans=0;
	
	while( i <= j )
	{
		if(price[i]+price[j]<=w)
		{
			++i;
			--j;
			//获得2个为一组的组 
			++ans;
		}
		/*
		1.选定了一个纪念品A,
		在剩余的纪念品中找不到可以与A匹配的纪念品B,
		使得A+B≤w,此时只能纪念品A单独分一组。
		这种情况容易理解。
		*/
		else
		{
			//最后1个只能单独1组 
			--j;
			++ans;
		}	
	}
	
	cout<<ans<<endl;
	
	return 0;
}
//细节决定成败 






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dllglvzhenfeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值