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();
    }
    
    
  • 相关阅读:
    北京燃气IC卡充值笔记
    随机分析、随机控制等科目在量化投资、计算金融方向有哪些应用?
    量化交易平台大全
    Doctor of Philosophy in Computational and Mathematical Engineering
    Institute for Computational and Mathematical Engineering
    Requirements for the Master of Science in Computational and Mathematical Engineering
    MSc in Mathematical and Computational Finance
    万字长文:详解多智能体强化学习的基础和应用
    数据处理思想和程序架构: 使用Mbedtls包中的SSL,和服务器进行网络加密通信
    31-STM32+W5500+AIR202/302基本控制篇-功能优化-W5500移植mbedtls库以SSL方式连接MQTT服务器(单向忽略认证)
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248155.html
Copyright © 2011-2022 走看看