Supermarket POJ - 1456

题目链接

题目大意:
给你n个商品:
每个商品有两个属性:
1,价值;2,最晚销售天数
且:每一天只可以买一件商品
求:可以获得的最大价值;
题目分析:
可以把这道题理解成了一道贪心的题目;
从这些商品里获得最大的价值;
既然是贪心,那么我的决策是什么:
尽量把价格高的卖出去
问题来了,在什么时候卖这些商品呢?
假如商品时间为n,那么销售的时间的区间是【1,n】,
最优的时间是什么呢?
当然是当天销售,这样对于同一天的商品来说,对价格排序后,肯定是价格高的先卖完。
当是如果这一天被占用了呢?
可以在【1,n-1】天里,找到一个距离n天最近的没有被占的时间,去销售;
那为什么不从前往后找呢?在第i天找,影响的是在【i,max】天销售的商品,i越大,影响的越小;

//暴力寻找[1,d-1]天内没被占用的天数;
还可以线段树查询;
//线段树维护距离n点最近的一个没被占的点的信息;

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int num=20012;
struct node
{
    int d,v;
}a[num];
bool vis[num];
bool cmp(node c,node b)
{
    return c.v > b.v;
}
//维护的是一棵树,k记录的这个区间最右边的非0的位置;
struct point
{
    int L,R,s;
}e[num<<2];
void update(int k)
{
    e[k].s=max(e[k<<1].s,e[k<<1|1].s);
    return ;
}
void build(int k,int L,int R)
{
    e[k].L=L;e[k].R=R;
    if(L==R) {
        e[k].s=R;
        return ;
    }

    int mid=(e[k].L+e[k].R)>>1;
    build(k<<1,L,mid);
    build(k<<1|1,mid+1,R);
    update(k);
    return;
}
void change(int k,int L,int R)
{
    if(e[k].R==R&&e[k].L==L)
    {
        e[k].s=0;
        return ;
    }
    int mid=(e[k].L+e[k].R)>>1;
    if(L<=mid) change(k<<1,L,R);
    if(R>mid)  change(k<<1|1,L,R);
    update(k);
    return ;
}
int search(int k,int L,int R)
{
    if(e[k].L>=L&&e[k].R<=R)
    {
        return e[k].s;
    }
    int mid=(e[k].L+e[k].R)>>1;
    int ans=0;
    if(L<=mid) ans=max(search(k<<1,L,R),ans);
    if(R>mid)  ans=max(search(k<<1|1,L,R),ans);
    return ans;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0){
            printf("0\n");
            continue;
        }

        memset(vis,0,sizeof(vis));
        int mx=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].v,&a[i].d);
            mx=max(mx,a[i].d);
        }

        sort(a+1,a+n+1,cmp);

        int ans=0;
        build(1,1,mx);

        for(int i=1;i<=n;i++)
        {
            if(!vis[a[i].d]){
                vis[a[i].d]=1;
                change(1,a[i].d,a[i].d);
                ans+=a[i].v;
            }
            else
            {
                if(a[i].d==1) continue;//[1,n]是按照价格的大小排序的 
                int pos=search(1,1,a[i].d);
                if(pos>0)
                {
                    change(1,pos,pos);
                    vis[pos]=1;
                    ans+=a[i].v;
                }

/*
                for(int j=a[i].d-1;j>=1;j--)
                {
                    if(!vis[j])
                    {
                        vis[j]=1;
                        ans+=a[i].v;
                        break;
                    }
                }
 */

            }

    	}
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值