rainbow的商店 贪心

描述

Rainbow开了一家商店,在一次进货中获得了N个商品。

已知每个商品的利润和过期时间。

Rainbow每天只能卖一个商品,并且过期商品不能再卖。

Rainbow也可以选择在每天出售哪个商品,并且一定可以卖出。

由于这些限制,Rainbow需要制定一份合理的售卖计划。请你计算一下,Rainbow最终可以获得的最大收益。

输入
第一行两个整数N。
接下来N行每行两个整数,分别表示每个商品的利润、过期时间。

1<=N,利润,时间<=10000。
输出

输出一个整数,表示Rainbow最终可以获得的最大收益。


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


一开始我的思路是:对每天将要过期的商品进行贪心,即每天都从当天将要过期的商品中选出价值最大的商品。这个思路显然是错的,提交上去之后,华丽丽的2分。仔细考虑一下,如果有两个价值100的商品都在第2天过期,一个价值10的商品在第一天过期,那么正确答案应当是选择两个100的商品,而不是第一天选择10,第二天选择100。


想通这一点之后,自然就明白该如何贪心了。正确的解法应当是:对商品的价值进行贪心,即尽量安排价值大的商品出售,最后再考虑价值小的。


那么如何“安排”商品的出售时间呢?


思路就是尽量在接近过期的时间出售该商品,这样就可以为过期时间早的商品留出选择的余地。


以测试样例为例,对7件商品进行降序排序:


价值:100 50 20 10 8 5  2

天数:  2   10 1   3  2 20 1


  1. 100->2(空),出售
  2. 50->10(空),出售
  3. 20->1(空),出售
  4. 10->3(空),出售
  5. 8->2(满)->1(满)->舍弃
  6. 5->20(空),出售
  7. 2->1(满)->舍弃
结果为 100 + 50 + 20 + 10 + 5 = 185

代码如下:

#include <iostream>
#include <algorithm>
using namespace std;

struct product{           // product记录商品的价值和过期时间
	int v;
	int t;
}p[10005];

int visited[10005];       // 记录某天是否已经安排出售其他商品
bool mycmp( struct product& a, struct product& b ){  // 定义比较函数
	return a.v > b.v || a.v == b.v && a.t < b.t;
}

int main(){
	int n;
	scanf("%d",&n);
	for( int i = 0; i < n; ++i )
		scanf("%d %d",&p[i].v,&p[i].t);
	sort(p,p+n,mycmp);             // 排序
	int j = 0, ans = 0;
	while( j < n ){                // 贪心
		for( int i = p[j].t; i > 0 ; --i ){ // 向前遍历,直到找到可以安排出售该商品的时间
			if( !visited[i] ){
				ans += p[j].v;
				visited[i] = 1;
				break;
			}
		}                                   // 否则,舍弃该商品
		++j;
	}
	printf("%d",ans);
	return 0;
}

算法正确性证明
 
1. 首先证明,存在一个最优解P,其出售的商品与算法的结果A选择的商品相同,经过有限次转换,可以令P安排出售商品的顺序与A相同。证明如下:
    假设P中商品i在第Pi天出售,在A中i在第Ai天出售(由于算法的安排策略,有Ai>=Pi),Pi != Ai。交换P中分别位于Pi和Ai的两个商品i和j,i的价值一定比j大。对于i,调换到Ai<=Deadlinei出售不会过期,对于j,调换到Pi<=Ai的位置出售时间提前,也不会过期。所以这样的转换不改变最终出售商品的总价值。
2.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值