1. 程式人生 > >【POJ 1456】Supermarket【兩種做法】【二叉堆貪心】【並查集】

【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;
}