POJ 1456 - Supermarket - [贪心+小顶堆]
题目链接: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 - [贪心+小顶堆]的更多相关文章
- CodeForces - 867E Buy Low Sell High (贪心 +小顶堆)
https://vjudge.net/problem/CodeForces-867E 题意 一个物品在n天内有n种价格,每天仅能进行买入或卖出或不作为一种操作,可以同时拥有多种物品,问交易后的最大利益 ...
- nyoj 208 + poj 1456 Supermarket (贪心)
Supermarket 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 A supermarket has a set Prod of products on sal ...
- POJ 1456 Supermarket(贪心+并查集优化)
一开始思路弄错了,刚开始想的时候误把所有截止时间为2的不一定一定要在2的时候买,而是可以在1的时候买. 举个例子: 50 2 10 1 20 2 10 1 50+20 50 2 40 ...
- POJ 2442 - Sequence - [小顶堆][优先队列]
题目链接:http://poj.org/problem?id=2442 Time Limit: 6000MS Memory Limit: 65536K Description Given m sequ ...
- HDU 4006The kth great number(K大数 +小顶堆)
The kth great number Time Limit:1000MS Memory Limit:65768KB 64bit IO Format:%I64d & %I64 ...
- heap c++ 操作 大顶堆、小顶堆
在C++中,虽然堆不像 vector, set 之类的有已经实现的数据结构,但是在 algorithm.h 中实现了一些相关的模板函数.下面是一些示例应用 http://www.cplusplus.c ...
- python 基于小顶堆实现随机抽样
起因:之前用蓄水池抽样,算法精简,但直观性很差. 所以这次采用了简单的,为没一个行,赋值一个随机值,然后取 最大的K个作为,随机样本. 基本思路:为每一个行(record,记录,实体) 赋一个rand ...
- Python使用heapq实现小顶堆(TopK大)、大顶堆(BtmK小)
Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) | 四号程序员 Python使用heapq实现小顶堆(TopK大).大顶堆(BtmK小) 4 Replies 需1求:给出N长 ...
- BZOJ 1150 - 数据备份Backup - [小顶堆][CTSC2007]
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1150 Time Limit: 10 Sec Memory Limit: 162 M De ...
随机推荐
- Mybatis3.3——源码阅读笔记
目录 Mybatis--Source阅读笔记 兵马未动,日志先行 异常 缓存 回收机制适配器 回收机制优化缓存 事务缓存 调试型缓存--日志缓存 解析 类型处理器 IO VFS Resource Re ...
- 如何永久删除git仓库中敏感文件的提交记录
如何永久删除git仓库中敏感文件的提交记录 参考: 1. https://help.github.com/articles/remove-sensitive-data/
- Selenium:注解@FindBy、@FindBys、@FindAll的用法
方式有3种:@FindBy.@FindBys.@FindAll.下文对3中类型的区别和使用场景进行介绍 1)@FindBy @FindBy(id= "A") private Web ...
- 2. Tensorflow的数据处理中的Dataset和Iterator
1. Tensorflow高效流水线Pipeline 2. Tensorflow的数据处理中的Dataset和Iterator 3. Tensorflow生成TFRecord 4. Tensorflo ...
- python 中的i++ ,逻辑表达式
1.关于i++ python 中的没有 i++ ,如果写了会报语法错误. 但是python 中有 --i,++i,+-i,-+i,他们不是实现-1操作的,仅仅是作为判断运算符号,类似数学中的负负得正 ...
- Mysql字符串字段中是否包含某个字符串,用 find_in_set
有这样一个需求,在Mysql数据库字符串字段(权限)中,有范围在 1 到 N 之间代表不同权限的值,分别被‘,’分开,现在要取出具有某权限的所有成员列表. 创建表: 1 CREATE TABLE ...
- Java知多少(43)异常处理基础
Java异常是一个描述在代码段中发生的异常(也就是出错)情况的对象.当异常情况发生,一个代表该异常的对象被创建并且在导致该错误的方法中被抛出(throw).该方法可以选择自己处理异常或传递该异常.两种 ...
- pip install psutil出错-You are using pip version 10.0.1, however version 18.0 is available.
今天想用python代替shell做运维相关的事,写代码都是在本机,调试在服务器上 C:\Users\0>pip install psutilRequirement already satisf ...
- plsql与64位的Oracle关联方法
在这里吐槽一下,plsql居然木有64位的,以前居然不知道,好久没用Oracle了,想练习一下,方法如下: 1.安装Oracle,官网都有,这里不细说了,我选的是64的Oracle安装的. 2.下载p ...
- 随笔:JS对象无new构造原理
var myFun = function(words) { if (!(this instanceof myFun)) { return new myFun(words); } this.name = ...