Supermarket POJ - 1456

题意:你现在有n个产品,每个产品有他的利润和他的保质期,在保质期以内将东西卖出就能够得到产品的利润,问你最大利润是多少(卖一个产品需要一天时间)

思路:看题就知道是贪心,我们按照利润大小的排序,之后先拿利润大的,如果当前天已经被占用,那么我们就一直往前推,直到遇到一个没有用过的天数把当前最大的卖掉就好了,先上贪心代码之后再讲这种东西怎么和并查集搞到一起了。

#include 
#include 
#include 
using namespace std;
const int maxn = 10000+10;
struct node
{
	int w,d;
}edg[maxn];
int vis[maxn];
bool cmp(node a,node b)
{
	return a.w>b.w;
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		memset(edg,0,sizeof(edg));
		for(int i = 0 ; i < n ; i++)
		{
			scanf("%d%d",&edg[i].w,&edg[i].d);	
		}
		memset(vis,0,sizeof(vis));
		sort(edg,edg+n,cmp);//从大到小排序 
		int ans = 0 ;
		for(int i = 0 ; i < n ; i++)
		{
			int d = edg[i].d;//获得当前的天数 
			while(vis[d])//如果这天被占用往前推一天 
			{
				d--;
			}
			if(d<=0) continue;
			vis[d] = 1;
			ans += edg[i].w;
			
		}
		printf("%d\n",ans);
	}
}

下面开始讲解如果用并查集去优化他,我们可以看到我们是如何获得到没有被占用的天数的?是一天一天的往后推对吧,那这样是不是很慢啊,我们如何快速得没有用过的当前天数的最小值?我们把当前天a 的前一天a-1 当做a的父亲,这样我们查找的时候就直接可以找到他的根节点,他肯定是个没有用过的点

#include 
#include 
#include 
using namespace std;
const int maxn = 10000+10;
int p[maxn];
void init()
{
	for(int i = 0 ; i < maxn ; i++)
	{
		p[i] = i;
	}
}
int getf(int x)
{
	return p[x] == x ? x : p[x] = getf(p[x]);
}
struct node
{
	int w,d;
}edg[maxn];
int vis[maxn];
bool cmp(node a,node b)
{
	return a.w>b.w;
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		init();
		memset(edg,0,sizeof(edg));
		for(int i = 0 ; i < n ; i++)
		{
			scanf("%d%d",&edg[i].w,&edg[i].d);	
		}
		memset(vis,0,sizeof(vis));
		sort(edg,edg+n,cmp);
		int ans = 0 ;
		for(int i = 0 ; i < n ; i++)
		{
			int dx = getf(edg[i].d);
			if(dx == 0) continue;
			p[dx] = dx-1;
			ans += edg[i].w;

		}
		printf("%d\n",ans);
	}
}


你可能感兴趣的:(Supermarket POJ - 1456)