【POJ 1456】Supermarket【两种做法】【二叉堆贪心】【并查集】

题意:

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

思路:

      先对所有的商品按照时间进行一下排序,再依次将商品加入优先队列,加入优先队列的时候需要进行一下判断:

1.当前商品的日期 == 优先队列中的商品数量 && 当前商品的价值大于小根堆堆顶元素的价值

      那么将堆顶元素弹出,并将当前商品加入优先队列

2.当前商品的日期 != 优先队列中的商品数量

      将当前商品加入优先队列

总结:

      本题就是一个贪心的做法,对于与时间排序发生冲突的商品,将冲突商品和之前商品的最小值进行比较,如果冲突商品权值更小,则将商品最小值弹出队列,最后队列中剩下的元素都是符合条件,并且最优的。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
typedef long long ll;
const int N = 1e4+100;

int n;
priority_queue<pair<int,int> > q;
pair<int,int> goods[N];

bool cmp(pair<int,int> a, pair<int,int> b)
{	
	return a.second < b.second;
}

int main()
{
	while(~scanf("%d",&n))
	{
		while(q.size()) q.pop();
		rep(i,1,n)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			goods[i] = make_pair(-x,y);
		}
		sort(goods+1,goods+1+n,cmp);
		rep(i,1,n)
		{
			if(goods[i].second == q.size() && goods[i].first < q.top().first)
			{
				q.pop();
				q.push(goods[i]);
			} 
			else if(goods[i].second != q.size()) q.push(goods[i]);
		}
		ll ans = 0;
		while(q.size())
		{
			ans += q.top().first;
			q.pop();
		}
		printf("%lld\n",-ans);
	}	
	return 0;
}

第二种做法:

思路:

      可以发现这道题每一个商品只会占用一个日期,因此对于商品的价值进行排序,只要这个商品可以选,那么就选这个商品。

那么本题就变成了一个简单的贪心算法,那和并查集有什么关系呢?

      我们继续看这个贪心算法,排序简单,但是如何判断这个商品可不可以选呢,就是如何判断这个商品过期之前的天数有没有空位呢?之前我们根据优先队列的大小进行了一次判断,现在我们通过并查集也可以实现这个判断。

      具体方法是,我们先给所有的日期建立一个数组,一开始每个日期都指向自己。

      每当读入一个商品时,我们去判断这个商品的日期是否指向0,如果指向0,代表这个商品之前的日期都已经被占满了,因此不可填。

      如果不是0,则代表这个商品可以填,那么我们就选取了这个商品,选取完这个商品之后,我们需要将这个 day = get( i ),day就是当前日期所指向的日期。

      将这个日期指向 fa[ i ] = get(day - 1),表示这个商品被选取了。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 10010;
typedef long long ll;

int fa[N],n;
pair<int,int> goods[N];

int get(int x)
{
	if(fa[x] == x) return x;
	else return fa[x] = get(fa[x]);
}

int main()
{
	while(~scanf("%d",&n))
	{
		int m = -1;
		rep(i,1,n)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			goods[i] = make_pair(-x,y);
			m = max(m,y);
		}
		sort(goods+1,goods+1+n);
		ll ans = 0;
		fa[0] = 0;
		rep(i,1,m) fa[i] = i;
		rep(i,1,n)
		{
			int day = get(goods[i].second);
			if(day == 0) continue;
			ans += goods[i].first;
			fa[day] = get(day-1);
		}	
		printf("%lld\n",-ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/82114953