题目链接:http://poj.org/problem?id=1456

Time Limit: 2000MS Memory Limit: 65536K

Description

A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Prod sold by a deadline dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products Sell ≤ Prod such that the selling of each product x∈Sell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling schedule is Profit(Sell)=Σx∈Sellpx. An optimal selling schedule is a schedule with a maximum profit.
For example, consider the products Prod={a,b,c,d} with (pa,da)=(50,2), (pb,db)=(10,1), (pc,dc)=(20,2), and (pd,dd)=(30,1). The possible selling schedules are listed in table 1. For instance, the schedule Sell={d,a} shows that the selling of product d starts at time 0 and ends at time 1, while the selling of product a starts at time 1 and ends at time 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80.

Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products.

Input

A set of products starts with an integer 0 <= n <= 10000, which is the number of products in the set, and continues with n pairs pi di of integers, 1 <= pi <= 10000 and 1 <= di <= 10000, that designate the profit and the selling deadline of the i-th product. White spaces can occur freely in input. Input data terminate with an end of file and are guaranteed correct.

Output

For each set of products, the program prints on the standard output the profit of an optimal selling schedule for the set. Each result is printed from the beginning of a separate line.

Sample Input

4 50 2 10 1 20 2 30 1

7 20 1 2 1 10 3 100 2 8 2
5 20 50 10

Sample Output

80
185

Hint

The sample input contains two product sets. The first set encodes the products from table 1. The second set is for 7 products. The profit of an optimal schedule for these products is 185.

题意:

给定 $n$ 个商品,每个商品有利润 $p_i$ 和过期时间 $d_i$,每天只能卖出一个商品,过期商品就不能在卖了,求如何安排每天卖的商品,使得利润最大。

题解:

很遥远的以前我们曾用贪心做过这道题目,大致思路是:优先考虑利润最大的商品,但是对每件商品尽可能安排越晚卖出越好,以方便给之后的商品留空间。时间复杂度 $O(n \log n + n \times max(d_i))$,

这次我们换一种更加直接贪心思路:假设当前是第 $k$ 天,那么当目前为止一共 $k$ 天时间,我要做的就是在保证不卖过期商品的前提下,尽可能的卖出利润前 $k$ 大的商品。

因此,我们可以把商品按照过期时间升序排序,并且建立一个初始为空的小顶堆(键值为商品的利润)来维护一个满足上述性质的方案:

  1、若当前商品的过期时间 $d_i$ 大于堆的 $size$,则直接入堆,代表安排卖出当前商品。

  2、若当前商品的过期时间 $d_i$ 等于堆的 $size$,则说明前 $d_i$ 天已经安排卖出了 $size$ 个商品,只有当我的利润大于堆中利润最小的,才考虑用当前商品替换掉堆中利润最小的商品。

  3、可以证明,不存在当前商品的过期时间 $d_i$ 小于堆 $size$ 的情况,因为最初堆 $size=0$,而 $d_i$ 最小为 $1$,因此第一个商品必然是情况1;而后,由于堆中节点是一个一个增加,而商品的遍历是过期时间单调不减的,因此必然存在第 $k$ 个商品使得 $d_k = size$(除非 $size$ 始终小于每个商品的过期时间),即产生情况2,那么根据情况2所描述的操作可知堆中元素不会再增加,而第 $k+1$ 个商品的过期时间必然不小于第 $k$ 个商品,因此在第 $k$ 个商品时必然有 $d_{k+1} \ge size$,以此类推易知始终达不到 $d_i < size$ 的情况。

最后,遍历完所有商品,堆中即存储了所有要安排卖出的商品,对这些商品的利润求和即得答案。时间复杂度 $O(n \log n)$。

AC代码:

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int maxn=+; struct Heap
{
int sz;
int heap[maxn];
void up(int now)
{
while(now>)
{
int par=now>>;
if(heap[now]<heap[par]) //子节点小于父节点,不满足小顶堆性质
{
swap(heap[par],heap[now]);
now=par;
}
else break;
}
}
void push(int x) //插入权值为x的节点
{
heap[++sz]=x;
up(sz);
}
inline int top(){return heap[];}
void down(int now)
{
while((now<<)<=sz)
{
int nxt=now<<;
if(nxt+<=sz && heap[nxt+]<heap[nxt]) nxt++; //取左右子节点中较小的
if(heap[now]>heap[nxt]) //子节点小于父节点,不满足小顶堆性质
{
swap(heap[now],heap[nxt]);
now=nxt;
}
else break;
}
}
void pop() //移除堆顶
{
heap[]=heap[sz--];
down();
}
void del(int p) //删除存储在数组下标为p位置的节点
{
heap[p]=heap[sz--];
up(p), down(p);
}
inline void clr(){sz=;}
}; int n;
vector<pii> P; //first为过期时间,second为利润
Heap h; int main()
{
while(cin>>n)
{
P.clear();
for(int i=,p,d;i<=n;i++)
{
scanf("%d%d",&p,&d);
P.push_back(make_pair(d,p));
}
sort(P.begin(),P.end()); h.clr();
for(int i=;i<P.size();i++)
{
if(P[i].first>h.sz) h.push(P[i].second);
else if(P[i].first==h.sz && P[i].second>h.top())
{
h.pop();
h.push(P[i].second);
}
} int sum=;
while(h.sz)
{
sum+=h.top();
h.pop();
}
printf("%d\n",sum);
}
}

POJ 1456 - Supermarket - [贪心+小顶堆]的更多相关文章

  1. CodeForces - 867E Buy Low Sell High (贪心 +小顶堆)

    https://vjudge.net/problem/CodeForces-867E 题意 一个物品在n天内有n种价格,每天仅能进行买入或卖出或不作为一种操作,可以同时拥有多种物品,问交易后的最大利益 ...

  2. nyoj 208 + poj 1456 Supermarket (贪心)

    Supermarket 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 A supermarket has a set Prod of products on sal ...

  3. POJ 1456 Supermarket(贪心+并查集优化)

    一开始思路弄错了,刚开始想的时候误把所有截止时间为2的不一定一定要在2的时候买,而是可以在1的时候买. 举个例子: 50 2  10 1   20 2   10 1    50+20 50 2  40 ...

  4. POJ 2442 - Sequence - [小顶堆][优先队列]

    题目链接:http://poj.org/problem?id=2442 Time Limit: 6000MS Memory Limit: 65536K Description Given m sequ ...

  5. HDU 4006The kth great number(K大数 +小顶堆)

    The kth great number Time Limit:1000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64 ...

  6. heap c++ 操作 大顶堆、小顶堆

    在C++中,虽然堆不像 vector, set 之类的有已经实现的数据结构,但是在 algorithm.h 中实现了一些相关的模板函数.下面是一些示例应用 http://www.cplusplus.c ...

  7. python 基于小顶堆实现随机抽样

    起因:之前用蓄水池抽样,算法精简,但直观性很差. 所以这次采用了简单的,为没一个行,赋值一个随机值,然后取 最大的K个作为,随机样本. 基本思路:为每一个行(record,记录,实体) 赋一个rand ...

  8. Python使用heapq实现小顶堆(TopK大)、大顶堆(BtmK小)

    Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) | 四号程序员 Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) 4 Replies 需1求:给出N长 ...

  9. BZOJ 1150 - 数据备份Backup - [小顶堆][CTSC2007]

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1150 Time Limit: 10 Sec Memory Limit: 162 M De ...

随机推荐

  1. 【C#】C#中的属性与字段

    目录结构: contents structure [+] 属性和字段的区别 无参属性 自动实现的属性 对象和集合初始化器 匿名类型 System.Tuple类型 有参属性 属性的可访问性 在这篇文章中 ...

  2. 分享一个Godaddy的优惠码,可以优惠35%——2013-11-23

    国外的域名注册商就是好,还有优惠码,付费的时候贴上优惠码就能免相应的金额,不错. 在网上找的一个35%优惠的优惠码,可以买域名和主机.(主机就免了,有点贵,域名不错) 我买了个com域名,原本$12. ...

  3. SNFAutoupdater通用自动升级组件V2.0

    1.组件介绍 C/S构的特点是能充分发挥客户端的处理能力,很多工作可以由客户端处理后再提交给服务器,对应的优点就是客户端响应速度快模式客户端以其强大的功能,丰富的表现力受到相当大部分用户的青睐,但是客 ...

  4. 第三部分:Android 应用程序接口指南---第一节:应用程序组件---第一章1-1.Fragment

    第1-1章 Fragments 在Activity中的fragment代表的是一种行为或用户界面的一部分.你可以在activity中结合多个fragments创建一个多面板UI,并可以在多个activ ...

  5. linux每日命令(37):top命令

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法.top是一个动态显示过程,即可以通过用户按键来不断刷新 ...

  6. 【Java】接口(interface)VS抽象类

    接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的.接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static f ...

  7. 阿里云 FTP 无法读取目录问题

    安全组除了添加制定 FTP端口外 需要加入再添加1024/65535端口 放行策略,ftp被动模式需要随机开一个此范围端口进行传输 添加安全组规则参考文档:https://help.aliyun.co ...

  8. Java知多少(92)滚动条

    滚动条(JScrollBar)也称为滑块,用来表示一个相对值,该值代表指定范围内的一个整数.例如,用Word编辑文档时,编辑窗右边的滑块对应当前编辑位置在整个文档中的相对位置,可以通过移动选择新的编辑 ...

  9. Matlab如何循环读取文件

    循环读取图片第一种方法①List =dir('*.jpg'); %如需其它图片格式支持,可以自己[重载dir()]函数,实现查找所有图片文件的功能,%如果图片是其它路径,可以用 ["路径&q ...

  10. volatile内存语义

    全面理解Java内存模型(JMM)及volatile关键字 volatile的内存语义 Volatile读写所建立的happens-before关系Volatile读写的内存语义 锁: 获取和释放Vo ...