题目链接:http://poj.org/problem?id=1456
题意:有n个物品(0 <= n <= 10000) ,每个物品有一个价格pi和一个保质期di (1 <= pi <= 10000, 1 <= di <= 10000),物品必须在保质期之前卖出。且每天只能卖出一个物品,问如何安排才能使卖出的总价格最大。
这道题贪心的思想很明显,先将物品的价格按照从大到小排序,再按照该顺序卖物品,如果存在不超过保质期的最大可用日期,则该物品能够卖出,并将这一天标记。关键在于如何找这个日期,就是在一个有序序列中查找小于等于当前日期的最大值,再将其删除,继续查找。这个可以用set来做。
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <stack>
#include <set>
#include <istream>
#include<queue>
#include<stack>
#include <cstring>
#include <string>
//#include <climits>
using namespace std;
struct products {
int money, day;
};
bool cmp(products a, products b) {
if (a.money != b.money)
return a.money > b.money;
return a.day>b.day;
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
set<int> s;
products *p = new products[n];
int md = 0;
for (int i = 0;i < n;i++) {
scanf("%d%d", &p[i].money, &p[i].day);
md = max(p[i].day, md);
}
for (int i = 1;i <= md;i++)
s.insert(i);
sort(p, p + n, cmp);
int ans = 0;
for (int i = 0;i < n && !s.empty();i++) {
if (*s.begin() > p[i].day)
continue;
set<int>::iterator iter = s.upper_bound(p[i].day);
iter--;
//cout << *iter << -1 << endl;
if (*iter <= p[i].day) {
ans += p[i].money;
s.erase(iter);
}
}
printf("%d\n", ans);
delete[]p;
}
}
除了这种解法外,我们还可以用并查集来维护,初始化每个日期i的父亲为自己,当当前的日期i被占用后,将其父亲设为前一天的日期i-1,每次查找i的最大可用日期即查找i的祖先即可,由于使用路径压缩,所以查找的复杂度很低,比用set块
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
class union_find_set {
public:
union_find_set(int n) {
fa = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++)
fa[i] = i;
}
~union_find_set()
{
delete fa,rank;
};
int find(int x) {
if (fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y)
return;
if (rank[x] < rank[y])
fa[x] = y;
else {
fa[y] = x;
if (rank[x] == rank[y])
rank[x]++;
}
}
bool same(int x, int y) {
if (find(x) == find(y))
return 1;
return 0;
}
int n;
int *fa,*rank;
};
struct products {
int money, day;
};
bool cmp(products a, products b) {
return a.money > b.money;
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
products *p = new products[n];
int md = 0;
for (int i = 0;i < n;i++) {
scanf("%d%d", &p[i].money,&p[i].day);
md = max(p[i].day, md);
}
union_find_set P(md + 1);
sort(p, p + n, cmp);
int ans = 0;
for (int i = 0;i < n;i++) {
int t = P.find(p[i].day);
if (t > 0) {
ans += p[i].money;
P.fa[t] = t - 1;
}
}
printf("%d\n", ans) ;
delete p;
}
}