【Ybtoj 第10章例5】超市购物【并查集】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

首先,我们很容易想到这道题的贪心思想,把所有的商品按收益排序,从前往后对每件商品进行抉择,对于第i件商品,如果存在期限内的某天还没有售卖商品,就选择可售卖该商品的最后一天卖掉它,然后将该天设置为已售卖。流程:从该商品的期限日期向前枚举日期,一旦遇到没有售卖的日期,就找到了答案。这样的时间复杂度为 O ( N 2 ) O(N^2) ON2

考虑优化时间复杂度:
我们发现,瓶颈在于查找每个商品可以被卖的最后日期。我们可以将每个日期抽象为一个集合,集合的代表即为整个集合唯一没有售卖过商品的日期。不难发现,每个集合的代表一定是集合的日期中最小的。这些日期显然可以用并查集维护。

SO,查找每个商品可以被卖的最后日期的流程为:
找出商品过期时间所在的集合的代表元素,如果其集合代表元素不为 0 0 0,则在其代表元素那天卖掉该商品。并将这个集合并入那天的前一天(代表元素的前一天)所在的集合中。


代码

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
using namespace std;

int n,p[10010],d[10010],fa[10010],maxn,ans;

struct c{
    
    
	int p,d;
}a[10010];

bool cmp(c l,c r)
{
    
    
	return l.p>r.p;
}

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

int main(){
    
    
	while(scanf("%d",&n))
	{
    
    
		maxn=0,ans=0;
		for(int i=1;i<=n;i++)
		{
    
    
			scanf("%d%d",&a[i].p,&a[i].d);
			maxn=max(maxn,a[i].d); 
		}
		sort(a+1,a+n+1,cmp);//从大到小
		for(int i=1;i<=maxn;i++)fa[i]=i;
		for(int i=1;i<=n;i++)
		{
    
    
			int x=find(a[i].d);
			if(x!=0)//看过期时间
			{
    
    
				ans+=a[i].p;
				fa[x]=x-1;//并入代表元素的前一天
			}
		}
		printf("%d\n",ans);
	}
}


猜你喜欢

转载自blog.csdn.net/kejin2019/article/details/115254534