zoukankan      html  css  js  c++  java
  • 超市

    超市

    有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();
    }
    
    
  • 相关阅读:
    Windows Internals学习笔记(八)IO系统
    FPGA相关术语(一)
    Bilinear Filter
    总线与接口
    GPIO相关知识
    .NET IL学习笔记(一)
    Windows Internals学习笔记(七)Image Loader
    Windows Internals学习笔记(五)Synchronization
    struts2官方 中文教程 系列五:处理表单
    struts2官方 中文教程 系列四:Action
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248155.html
Copyright © 2011-2022 走看看