【POJ 1456】Supermarket【并查集】

题意:

       给定N个商品,每个商品利润为pi,过期时间为di,每天只能卖一个商品,过期商品不能再卖,求如何安排每天卖的商品,可以使收益最大。 1 <= N, pi, di <= 10000.

 

思路:

        首先有一个很明显的贪心思路。就是将商品按照日期从先到后排序,然后遍历每一个商品,如果当前这个商品过期时间之前的每一天没有全部安排完,那就将这个商品选中。如果这个商品过期时间之前已经满了,那就在前面挑一个价值最小的商品换出来,然后再将当前这个商品放回去。因此维护一个堆就可以了。

        但是这题还可以用并查集来思考,用并查集来维护每一个数组被使用的情况。即先将商品按照利润排序,然后贪心的先将利润大的商品卖出。因此我们需要判断对于当前这个商品来说,过期日期之前是否还有空余天数来将这个商品卖出,因此可以用并查集来维护数组中的每一个位置。例如3、4、5、6天都已经安排了商品,则当前又进入一个商品,过期时间为第4天,则查询第4天的并查集,直接返回第二天,即可完成本题。

 

代码:

#include 
#include 
#include 
#include 
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 1e4+1000;

int p[N],n;
struct Node{
	int v,d;
	bool operator < (Node x) const {
		return v > x.v;
	}
}t[N];

int find(int x) {
	return p[x]==x?x:p[x]=find(p[x]);
}

void merge(int x,int y){
	int r1=find(x),r2=find(y);
	if(r1!=r2){
		p[r1]=r2;
	}
}

void solve()
{
	p[0] = 0; int ans = 0;
	rep(i,1,n){
		int pos = find(t[i].d);
		if(pos != 0) ans += t[i].v, merge(pos,pos-1);
	}
	printf("%d\n",ans);
}

int main()
{
	while(~scanf("%d",&n))
	{
		rep(i,1,n) scanf("%d%d",&t[i].v,&t[i].d);
		rep(i,0,1e4) p[i] = i;
		sort(t+1,t+1+n);
		solve();
	}	
	return 0;
}

 

你可能感兴趣的:(#,并查集,数据结构)