284. 超市卖货-----HZOJ

一、题目:

超市里有N个商品. 第i个商品必须在保质期(第di天)之前卖掉, 若卖掉可让超市获得pi的利润.

​ 每天只能卖一个商品.

​ 现在你要让超市获得最大的利润.

输入

​ 每组数据第一行为一个整数N(0<N≤10000), 即超市的商品数目

​ 之后N行,每行各有两个整数, 第i行为pi,di(1<=pi,di<=10000)

输出

​ 输出当前条件下超市的最大利润.

二、样例:

输入:
7
20 1 
2 1 
10 3 
100 2 
8 2 
5 20 
50 10
输出: 
185

三、题目分析: 

由题目可知,超市里有N个商品,第i个商品必须在保质期第di天前卖掉,比如说,假如有第7个商品,就要在第7天前(包括第7天)卖掉这个商品,一天只能卖一个商品。且,第di天卖的第i个商品必须让超市获得最大利润,也就是说,假如有7个商品,那么这7个商品必须在第7天前(包括第7天)卖掉并获得最大总利润。那么要最大总利润,就要卖掉的每个商品获得最大利润。

比如说:

上面的输入案例中,有两件还有一天就过期的商品。其中,一件商品利润为20,另一件利润为2,那么超市为了取得最大利润,就会上架可以获取利润为20的商品,以此类推。

最后的最大利润为:20(d1)+10(d3)+100(d2)+5(d20)+50(d10)=185

四、解决思路分析: 

通过上面的题目分析,相信你已经对题目的要求有了一定的了解。在这个基础上,该如何编写代码来解决这个问题呢?

首先,我们需要输入一个数作为超市的商品数目,其次输入N行,各有两个整数, 第i行为pi,di(1<=pi,di<=10000)。根据题目要求,需要对已经输入过期的天数或利润进行排序,再根据之后商品过期的天数利润决定:

(1)如果商品的过期天数大于当前商品的最大过期天数第di天,则可以直接上架,因为超市可以在该商品的过期日期前卖掉
(2)如果商品的过期天数等于当前商品的最大过期天数第di天,则替换掉已上架商品的利润最小者,利润大者上架。
(3)如果商品的过期天数小于当前商品的最大过期天数第di天,要么该商品已经上架,要么该商品已经过期,比如说,有一件将在3天后过期的商品上架了,这时来了一件将在2天后过期的商品,超市对已经快要过期的商品已经进行了过期天数和利润的排序,要么就已在餐桌上和菜单上了,要么就是已经过期了。

那么不用考虑最后一种情况。

在这个过程中,由于我们要对过期天数及利润进行从小到大的维护,所以需要使用一个排序算法或结构来维护。在这里,使用的是小顶堆(set有序集合)。

五、 代码及说明:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<stack>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
typedef struct data{ //定义一个结构体作为一件商品
	data(int p,int d):p(p),d(d){} //定义一个有参构造方法,赋值
	int p; //商品的利润
	int d; //商品将在第d天后过期
	bool operator<(const data &obj)const{ //重载一个小于运算符
		if(d!=obj.d)return d<obj.d; //过期天数按照从小到大比较排序,同号<
		return p>obj.p; //商品利润按照从大到小排序,异号>
	}
}data;

typedef pair<int,int>pir; //用于记录第几个商品的大利润,第一个参数为利润,第二个参数为第几个商品

int main(){
	int  n1;
	cin>>n1; //输入超市有n1个商品
	vector<data>arr;//用于存储这些商品
	set<pir>s;//小顶堆,用于存储上架最大利润,同时过期天数符合的商品
	for(int i=0,p,d;i<n1;i++){
		cin>>p>>d; //输入商品的利润、过期天数
		arr.push_back(data(p,d)); //存储这些商品信息
	}
	sort(arr.begin(),arr.end()); //根据重载方法对这些商品信息进行排序
	for(int i=0;i<n1;i++){
		if(arr[i].d>s.size()){ //该商品过期天数大于当前保质期第di天(保质期=1,则为1天,类比size)
			s.insert(pir(arr[i].p,i)); //存储商品的利润并按利润从小到大排序,及第几个商品
		}else if(arr[i].d==s.size()){ //过期天数等于当前保质期第di天
			if(arr[i].p>s.begin()->first){ //该商品利润大于上架商品最小利润
				s.erase(s.begin()); //删除已上架最小利润的商品
				s.insert(pir(arr[i].p,i)); //上架该商品
			}
		}
	}
	int ans=0;
	for(auto x:s){ //遍历已上架的商品
		ans+=x.first; //计算总最大利润
	}
	cout<<ans<<endl;
	return 0;
}

文章到从结束!

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值