POJ_1456 Supermarket

这是一个关于如何确定超市商品销售顺序以最大化利润的问题。每个商品有利润和销售截止日期,每天只能销售一个商品。需要找到最佳的销售计划,使得总利润最大。输入包含商品数量及其利润和截止日期,输出是最佳销售计划的利润。可以通过使用小根堆,按截止日期排序并比较商品价值来求解。

Supermarket

链接

POJ_1456 Supermarket

Description

A supermarket has a set Prod of products on sale. It earns a profit p x p_x px for each product x ∈ P r o d x \in Prod xProd sold by a deadline d x d_x dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products S e l l ≤ P r o d Sell \leq Prod SellProd such that the selling of each product x ∈ S e l l x \in Sell xSell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling schedule is P r o f i t ( S e l l ) = ∑ x ∈ S e l l p x Profit(Sell)=\sum_{x∈Sell} px Profit(Sell)=xSellpx. An optimal selling schedule is a schedule with a maximum profit.

For example, consider the products P r o d = { a , b , c , d } Prod=\left\{a,b,c,d\right\} Prod={a,b,c,d} with ( p a , d a ) = ( 50 , 2 ) \left(p_a,d_a\right)=\left(50,2\right) (pa,da)=(50,2), ( p b , d b ) = ( 10 , 1 ) \left(p_b,d_b\right)=\left(10,1\right) (pb,db)=(10,1), ( p c , d c ) = ( 20 , 2 ) \left(p_c,d_c\right)=\left(20,2\right) (pc,dc)=(20,2), and ( p d , d d ) = ( 30 , 1 ) \left(p_d,d_d\right)=\left(30,1\right) (pd,dd)=(30,1). The possible selling schedules are listed in table 1 1 1. For instance, the schedule S e l l = { d , a } Sell=\left\{d,a\right\} Sell={d,a} shows that the selling of product d d d starts at time 0 0 0 and ends at time 1 1 1, while the selling of product a a a starts at time 1 1 1 and ends at time 2 2 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80 80 80.

table 1

Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products.

题目大意:超市里有 N N N件商品,每件商品都有利润 p i p_i pi和过期时间 d i d_i di,每天只能卖一件商品,过期商品不能再卖。

求合理安排每天卖的商品的情况下,可以得到的最大收益是多少。

Input

A set of products starts with an integer 0 ≤ n ≤ 10000 0 \leq n \leq 10000 0n10000, which is the number of products in the set, and continues with n pairs pi di of integers, 1 ≤ p i ≤ 10000 1 \leq p_i \leq 10000 1pi10000 and 1 ≤ d i ≤ 10000 1 \leq d_i \leq 10000 1di10000, that designate the profit and the selling deadline of the i i i-th product. White spaces can occur freely in input. Input data terminate with an end of file and are guaranteed correct.

Output

For each set of products, the program prints on the standard output the profit of an optimal selling schedule for the set. Each result is printed from the beginning of a separate line.

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

Hint

The sample input contains two product sets. The first set encodes the products from table 1 1 1. The second set is for 7 7 7 products. The profit of an optimal schedule for these products is 185 185 185.

思路

先建立一个小根堆。

把所有的产品按照过期时间排序,然后遍历每一件产品。

若某产品的过期时间等于堆中的产品数,即这件产品如果再不卖就会过期,那么将它与堆顶价值最小的产品比较。如果该产品的价值比堆顶产品的价值还高,说明此方案更优。这时就要删除堆顶,将该产品的价值加入堆。

若某产品的过期时间大于堆中的产品数,即这件产品在堆中所有产品卖完后依然不会过期。这时就要直接将该产品加入堆。

最后堆中所有产品的价值之和即位所求答案。

这是第一次做堆的题目,所以堆是手写的。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const ll N=10000;
struct str{
	ll p,d;
}prod[N+1];
ll n,h_cnt,ans,heap[N+1];
bool cmp(str a,str b)
{
	return a.d<b.d;
}
void up(ll p)//将堆中的某一个元素上移直至满足小根堆的性质
{
	while(p>1)
	{
		if(heap[p]<heap[p/2])//子节点<父节点
		{
			swap(heap[p],heap[p/2]);
			p=p>>1;
		}
		else
			break;
	}
	return;
}
void down(ll p)//将堆中的某一个元素下沉直至满足小根堆的性质
{
	ll s=p*2;//s是p的儿子 
	while(s<=h_cnt)
	{
		if(s<h_cnt&&heap[s]>heap[s+1])//取左右儿子中较小的那个 
			s++;
		if(heap[s]<heap[p])
		{
			swap(heap[s],heap[p]);
			p=s,s=p<<1;
		}
		else
			break;
	}
	return;
}
void h_insert(ll val)//向堆中插入一个带有权值的节点 
{
	h_cnt++;
	heap[h_cnt]=val;
	up(h_cnt);
	return;
}
void h_extract()//删除堆顶节点 
{
	heap[1]=heap[h_cnt];
	heap[h_cnt]=0;
	h_cnt--;
	down(1);
	return;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	while(cin>>n)//这里只能写cin,否则会无法判断是否有输入
	{
		h_cnt=0;
		memset(heap,0,sizeof(heap));
		for(ll i=1;i<=n;i++)
			scanf("%lld%lld",&prod[i].p,&prod[i].d);
		sort(prod+1,prod+n+1,cmp);
		for(ll i=1;i<=n;i++)
		{
			if(prod[i].d==h_cnt&&heap[1]<prod[i].p)//将要过期且比堆顶更优 
			{
				h_extract();//移除堆顶
				h_insert(prod[i].p);//将当前产品的价值插入堆 
			}
			if(prod[i].d>h_cnt)//不可能过期
				h_insert(prod[i].p); 
		}
		ans=0;
		while(h_cnt)
		{
			ans=ans+heap[1];
			h_extract();
		}
		printf("%lld\n",ans);
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值