1. 程式人生 > >二叉堆_貪心_POJ1456_Supermarket

二叉堆_貪心_POJ1456_Supermarket

點此開啟題目頁面

思路分析:

    將所有商品按照保質期非遞減排序得序列A[1...n], 設H為初始為空的最小堆. 執行下述虛擬碼所述貪心過程:

for i = 1 to n
	if A[i]的保質期 > H.size
		H.push(A[i]的利潤)
	else
		if A[i].利潤 > H.top()
			H.pop(), H.push(A[i]的利潤)

    容易證明上述過程滿足迴圈不變式, i >= 2時, 每次第1行迴圈頭檢測之前, H中元素對應的集合為A[1...i - 1]中可獲得最大利潤的售出方案對應的售出商品集合.

    下面給出AC程式碼:

//POJ1456_Supermarket
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int MAX = 1e4 + 5;
pair<int, int> pro[MAX];//first:保質期, second:利潤
int main(){
	int n;
	while(~scanf("%d", &n)){
		for(int i = 1; i <= n; ++i) scanf("%d %d", &pro[i].second, &pro[i].first);
		sort(pro + 1, pro + n + 1);
		priority_queue<int> heap;
		for(int i = 1; i <= n; ++i)
			if(pro[i].first > heap.size()) heap.push(-pro[i].second);
			else if(pro[i].second > -heap.top()) heap.pop(), heap.push(-pro[i].second);
		int ans = 0; while(!heap.empty()) ans += -heap.top(), heap.pop();
		cout << ans << endl;
	}
	return 0;
} 

另外, 本題使用muitiset也可直接AC, 程式碼如下:

//POJ1456_Supermarket
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
const int MAX = 1e4 + 5;
pair<int, int> pro[MAX];//first:保質期, second:利潤
int main(){
	int n;
	while(~scanf("%d", &n)){
		for(int i = 1; i <= n; ++i) scanf("%d %d", &pro[i].second, &pro[i].first);
		sort(pro + 1, pro + n + 1);
		multiset<int> heap;
		for(int i = 1; i <= n; ++i)
			if(pro[i].first > heap.size()) heap.insert(pro[i].second);
			else if(pro[i].second > *heap.begin()) heap.erase(heap.begin()), heap.insert(pro[i].second);
		int ans = 0; for(multiset<int>::iterator it = heap.begin(); it != heap.end(); ++it) ans += *it;
		cout << ans << endl;
	}
	return 0;
}