poj1456 贪心+并查集

Posted dlutjwh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj1456 贪心+并查集相关的知识,希望对你有一定的参考价值。

题目链接: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
", 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
", ans) ;
		delete p;
	}
}

  

以上是关于poj1456 贪心+并查集的主要内容,如果未能解决你的问题,请参考以下文章

POJ1456:Supermarket(并查集+贪心)

[POJ1456]Supermarket(贪心 + 优先队列 || 并查集)

poj 1456(贪心并查集)

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

POJ 1456 Supermarket(贪心+并查集)

poj1456 贪心+并查集