超市

超市

有n件商品,第i件商品标记为((d_i,p_i)),表示该件商品保质期(d_i)天,价值(p_i),现在从第一天开始,每天只能卖一件商品,请最大化收益,(nleq 10000)

这显然是一道集合的题目,无序的话,首先考虑排序,转为有序的数列

法一:按(p_i)从大到小排序

从数列前往后扫描,容易知道第一件商品价值最大,朴素的思想告诉我们要选择这一件商品,但是一定会最优吗?从答案的角度看问题,把每一天想象为一个盒子,而每件商品为一个球,某些商品只能放在前面特定的盒子。

在最终的方案中,盒子应该被放的不能再放任何球进入,现在回到问题来,如果不选这个球,就代表,腾出这个盒子给了别的球,而别的球价值显然低了,于是结果肯定不优秀。

现在问题显然是球应该放到哪一天?朴素的思想告诉我们应该放在可以放的天数中尽可能靠后的天,因为对于两天(x,y,x<y)而言,后面的盒子只有三种可能,(x,y)都可以选择,(x)能选择,(y)不能选择,(x,y)都能选择,无论哪种情况,结果一定是最优秀的。

因此我们只需要从前往后扫描,把能选的都选了,选的天数尽可能靠后即可,为了优化(O(n^2))扫描,你可以利用线段树,但是不好写,我们不妨利用平衡树,把每一天的编号加入树中,如果某一天选择卖出一件商品的话,就在树中删除对应的天的编号,如果需要查询是否它是否可以选择,只要把其对应的保质期在平衡树查找第一个小于等于它的即可,时间复杂度(O(nlog(n))),常数太大了,作为比较差劲的法一。

参考代码:

#include <iostream>
#include <cstdio>
#include <set>
#include <cstring>
#include <algorithm>
#define il inline
#define ri register
#define Size 15000
using namespace std;
struct item{
	int p,d;
	il bool operator<(const item&x)const{
		return p>x.p;
	}
}I[Size];
set<int>S;
set<int>::iterator m;
il void read(int&);
int main(){int n;
	while(scanf("%d",&n)!=EOF){int ans(0);S.clear();
		for(int i(1);i<=10000;++i)S.insert(i);
		for(int i(1);i<=n;++i)read(I[i].p),read(I[i].d);
		sort(I+1,I+n+1);
		for(int i(1);i<=n;++i){
			m=S.upper_bound(I[i].d);
			if(m==S.begin())continue;
			S.erase(--m),ans+=I[i].p;
		}printf("%d
",ans);
	}
	return 0;
}
il void read(int &x){
	x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

法二:按(d_i)

从数列前往后扫描,你只知道,这一件物品保质期是最短的,如果说法一是最优性贪心(就是按最优候选人选到最差候选人,能选的都选,比如krucal算法),那么法二就是替换性贪心,通俗地讲,也就是一开始做的不一定是最优决策,但是后面会不断替换最差解,从而使结果最优。

不妨维护一个小根堆,排序关键字为(d_i),从前往后扫描数列,显然堆中元素个数总是小于当前商品的保质期,如果该件商品的保质期大于堆中元素个数,加入堆中,否则就不得不替换一件商品,显然是替换最差劲的商品,也就是堆顶,因此就可以做到常数比较小的(O(nlog(n)))(法一用到了天数这个条件,所以萎了)。

顺便提一下,为什么不按(d_i)排序不行?因为替换性贪心有一个前提,你要能够替换,如果不按(d_i)排序最终导致,你替换了不能替换的比如你只有1天保质期,而你替换了有几十天保质期,又靠后的商品。

参考代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define il inline
#define ri register
#define Size 10500
#define swap(x,y) x^=y^=x^=y
using namespace std;
struct big{
	int a[Size],n;
	il void push(int x){
		a[++n]=x;int p(n);
		while(p>1)
			if(a[p>>1]>a[p])
				swap(a[p>>1],a[p]),
					p>>=1;
			else break;
	}
	il void pop(){
		swap(a[1],a[n]),--n;
		int p(1),s(p<<1);
		while(s<=n){
			if(s<n&&a[s+1]<a[s])++s;
			if(a[s]<a[p])swap(a[s],a[p]),
							 p=s,s=p<<1;
			else break;
		}
	}
}B;
struct pi{int p,d;
	il bool operator<(const pi&x)const{
		return d<x.d;
	}
}p[Size];
il void read(int&);
int main(){int n;
	while(scanf("%d",&n)!=EOF){
		for(int i(1);i<=n;++i)
			read(p[i].p),read(p[i].d);
		sort(p+1,p+n+1);
		for(int i(1);i<=n;++i){
			if(p[i].d>B.n)B.push(p[i].p);
			else if(B.a[1]<p[i].p)
				B.pop(),B.push(p[i].p);
		}int ans(0);
		for(int i(1);i<=B.n;++i)
			ans+=B.a[i];printf("%d
",ans),B.n=0;
	}
	return 0;
}
il void read(int &x){
	x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248155.html