AcWing 145. 超市
类型:二叉堆
原题链接:https://www.acwing.com/problem/content/description/147/
题目:
超市里有 N 件商品,每件商品都有利润 pi 和过期时间 di
,每天只能卖一件商品,过期商品不能再卖。
求合理安排每天卖的商品的情况下,可以得到的最大收益是多少。
输入格式
输入包含多组测试用例。
每组测试用例,以输入整数 N
开始,接下来输入 N 对 pi 和 di,分别代表第 i
件商品的利润和过期时间。
在输入中,数据之间可以自由穿插任意个空格或空行,输入至文件结尾时终止输入,保证数据正确。
输出格式
对于每组产品,输出一个该组的最大收益值。
每个结果占一行。
数据范围
0≤N≤10000
,
1≤pi,di≤10000
最多有 14
组测试样例
输入样例:
4 50 2 10 1 20 2 30 1
7 20 1 2 1 10 3 100 2 8 2
5 20 50 10
输出样例:
80
185
思路:
用一个堆表示卖出的商品,每个对代表商品的价值,堆的大小代表到第几天,这样一来,堆的和就是到某一天为止卖出的商品的利润和,选择下一件商品插入堆中,就是在前几天中应该卖出的商品中的一件。
举个例子:
4 50 2 10 1 20 2 30 1
排序后:10,1 30, 1 50,2 20,2
开始遍历维护堆:
【10,1】:堆为空,还没有选择任何商品,直接选择,即插入堆
10
/
NULL NULL
【30,1】:堆不为空,堆大小为1,也就是卖出了一天的商品,当前选择的商品也限于前1天卖,所以和堆顶元素比较,所得利润更高,前一天卖出的商品价格最低的改为30,
30
/
NULL NULL
【50,2】:堆不空,当前商品期限为2天,不破坏之前卖出的商品,直接卖,也就是插入到堆中,
30
/
50 NULL
【20,2】:堆不空,当前商品期限为2天,堆大小为2,已经决定卖出2件商品,当前商品和之前卖出的商品最小利润的比较决定是否替换之前最小利润的商品(第二天的不论是替换了第一天的商品或者是第二天的商品都是正确的,堆中的商品都是可以出售的),堆中最小为30,不替换。
图同上。
有一点需要注意的是,如果替换了堆顶的元素,需要维护堆的结构,第一次写的时候取最小值是直接取的堆顶却在替换的时候忘记维护堆的结构,一直是错的
代码实现:
手动实现堆:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef pair<int, int> P;
const int MAX = 10005;
int n;
int heap[MAX]; // 大小不好确定,最坏情况2^10000
P arr[MAX];
int cnt = 0, root = 1;
bool cmp(P p1, P p2){
if(p1.second == p2.second){
return p1.first > p2.first;
}
return p1.second < p2.second;
}
void up(int pos){
while(pos != root){
int p = pos/2;
if(heap[pos] < heap[p]){
swap(heap[pos], heap[p]);
pos /= 2;
}else{
return;
}
}
}
void insert(int x){
heap[++cnt] = x;
up(cnt);
}
int get_sum(int x){
if(x > cnt)return 0;
int res = heap[x];
res += get_sum(x * 2);
res += get_sum(x * 2 + 1);
return res;
}
void down(int pos){
while(pos < cnt){
int l = pos * 2, r = pos * 2 + 1, m = pos;
if(l <= cnt && heap[l] < heap[m]){
m = l;
}
if(r <= cnt && heap[r] < heap[m]){
m = r;
}
swap(heap[pos], heap[m]);
if(m == pos) break;
pos = m;
}
}
int main(){
int a, b;
while(cin>>n){
for(int i = 0; i < n; i++){
// cin>>a>>b;
scanf("%d%d", &a, &b);
arr[i] = P(a, b);
}
sort(arr, arr + n, cmp);
for(int i = 0; i < n; i++){
P p = arr[i];
if(p.second == cnt && p.first > heap[root]){
heap[root] = p.first;
down(root);
}else if(p.second > cnt){
insert(p.first);
}
}
cout<<get_sum(root)<<endl;
cnt = 0;
}
return 0;
}
或者直接用stl的优先队列实现
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
int n;
vector<P> arr;
priority_queue<int, vector<int>, greater<int> > que;
bool cmp(P p1, P p2){
if(p1.second == p2.second){
return p1.first > p2.first;
}
return p1.second < p2.second;
}
int main(){
int a, b;
while(cin>>n){
arr.clear();
for(int i = 0; i < n; i++){
cin>>a>>b;
arr.push_back(P(a, b));
}
sort(arr.begin(), arr.end(), cmp);
for(int i = 0; i < n; i++){
if(arr[i].second == que.size() && arr[i].first > que.top()){
que.pop();
que.push(arr[i].first);
}else if(arr[i].second > que.size()){
que.push(arr[i].first);
}
}
int res = 0;
while(!que.empty()){
res += que.top();
que.pop();
}
cout<<res<<endl;
}
return 0;
}