G - Supermarket POJ - 1456(并查集 优先队列两种写法)

超市里有N个商品. 第i个商品必须在保质期(第di天)之前卖掉, 若卖掉可让超市获得pi的利润.
每天只能卖一个商品.
现在你要让超市获得最大的利润.

Input

多组数据.
每组数据第一行为一个整数N (0 <= N <= 10000), 即超市的商品数目
之后N行各有两个整数, 第i行为 pi, di (1 <= pi, di <= 10000)

Output

对于每一组数据, 输出当前条件下超市的最大利润

Sample Input

4
50 2
10 1
20 2
30 1

7
20 1
2 1
10 3
100 2
8 2
5 20
50 10

Sample Output

80
185

分析:这是道简单贪心+并查集。首先超市要获取最大利润,那么我们就把价值最大的放在最前面进行判断,当然尽可能的在他规定的最后一天卖出去最好,假设这一天已经有商品卖出去了,那就搜索前一天是否有卖出去的(类似于记忆化搜索)。

代码:

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include<iostream>
#include <map>
#include <vector>
#include <algorithm>
#define accept return 0
#define  mes(a, b)  memset(a, b, sizeof a)
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e5 + 10;
const int    maxm = 1e5 + 10;
const int    mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int pre[maxn],n;

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

struct node{
	int val,day;
}g[maxn];

int cmp(node a,node b){
	return a.val > b.val;
}

void init(){
	for(int i = 0; i < maxn;i++) pre[i] = i; 
}

int main(){
        while(cin >> n){
		for(int i = 1;i <= n;i++){
			cin >> g[i].val >> g[i].day;	
		}
		sort(g + 1,g + n + 1,cmp);
		int ans = 0;
		init();
		for(int i = 1 ;i <= n;i++){
			int temp = find(g[i].day);
			if(temp == 0) continue;
			else {
				pre[temp] = find(temp - 1);
                        //压缩路径  当天已被使用后,pre的值变为前一天的根节点
				ans += g[i].val;
			}
		}
		cout << ans << endl;
	}
} 

同理,这题也可以用优先队列优化,思路如下:

从最大天数开始从后往前维护每天的最大值,那所有符合条件的数全部放入优先队列当中,每天只取一件,取出的就是符合条件的最大的价值的商品。

例如样例2:排序后的结果为:

5 20

50 10

10 3

100 2

8 2

20 1

2 1
因此,第20天队列中元素为 5 20,因此取5,ans += 5;
.
.
.
.
.
第2天队列中元素为 100 2
8 2
因此取100,ans += 100;

第1天队列中元素为 20 1
8 2
2 1
因此取20,ans += 20;
代码如下:

    #include<queue>
	#include <cstdlib>
	#include <cstdio>
	#include <cstring>
	#include <cmath>
	#include<iostream>
	#include <map>
	#include <vector>
	#include <algorithm>
	#define accept return 0
	#define  mes(a, b)  memset(a, b, sizeof a)
	typedef unsigned long long int ull;
	typedef long long int ll;
	const int    maxn = 1e4 + 10;
	const int    maxm = 1e5 + 10;
	const int    mod  = 1e9 + 7;
	const ll     INF  = 1e18 + 100;
	const int    inf  = 0x3f3f3f3f;
	const double pi   = acos(-1.0);
	const double eps  = 1e-8;
	using namespace std;
	
	struct node{
		int val,day;
		bool operator <( node a)const{
			return val < a.val;
		}
	}pp,ans[maxn];
	
	int cmp(node a,node b){
		return a.day > b.day;
	}
	
	int solve(int n){
		priority_queue<node>q;
		int maxd,maxv = 0,t1,i = 0;
		for(int maxd = ans[0].day; maxd > 0;maxd--){
			for(;i < n &&maxd <= ans[i].day;i++){
				pp.val = ans[i].val;
				q.push(pp);
			}
			t1 = 0;
			while(!q.empty() && t1 < 1){
				pp = q.top();
				maxv += pp.val;
				q.pop();	
				t1++;
			}
		}
		return maxv;	
	}
	
	int main(){
		int n;
		while(cin >> n){
			for(int i = 0;i < n;i++){
				cin >> ans[i].val >> ans[i].day;
			}
			sort(ans,ans + n,cmp);
			printf("%d\n",solve(n));
		}
		return 0;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值