[CF19B]Checkout Assistant

题目描述

Bob 来到一家现购自运商店,将 n 件商品放入了他的手推车,然后到收银台 付款。每件商品由它的价格 pi 和收银员扫描它的时间 ti 秒定义。当收银员正在扫 描某件商品时,Bob 可以从他的手推车中偷走某些其它商品。Bob 需要恰好 1 秒 来偷走一件商品。Bob 需要付给收银员的最少钱数是多少?请记住,收银员扫描 商品的顺序由 Bob 决定。

输入格式

输入第一行包含数 n(1≤n≤2000)。接下来 n 行每行每件商品由 一对数 ti,ci(0≤ti≤2000,1≤ci≤10^9)描述。如果 ti 是 0,那么当收银员扫描 商品i时,Bob 不能偷任何东西。

输出格式

输出一个数字——Bob需要支付的最小金额是多少。

样例输入

4
2 10
0 20
1 5
1 3

样例输出

8

题解

这道题可以看成是一个背包问题来做即可。
我们将总时间看成是将所有物品都交给收银员扫描的情况下需要的时间,每一件物品的体积v[i]看作是偷取这件物品所需要的时间+扫描时间,因为我们选取一件物品后这件物品就不会再被扫描了。这样我们就可以得到我们能够赚取的最大金额,再用所有物品的总价值减去这个最大金额就可以得到答案了。

#include<bits/stdc++.h>
#define maxn 5005
using namespace std;
inline char get(){
    static char buf[300000],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,300000,stdin),p1==p2)?EOF:*p1++; 
}
inline long long read(){
    register char c=get();register long long f=1,_=0;
    while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
    while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
    return _*f;
}
long long n;
long long t[maxn],c[maxn];
//?????????? 
long long V,C;
long long v[maxn];
long long dp[2005*4005];
int main(){
    //freopen("1.txt","r",stdin);
    n=read();
    long long out=0;
    for(register long long i=1;i<=n;i++)t[i]=read(),c[i]=read(),v[i]=t[i]+1,V+=t[i],C+=c[i];
    //V+=n;
    long long note=0;
    for(register long long i=1;i<=n;i++){
        for(register int j=V;j>=v[i];j--){
            dp[j]=max(dp[j],dp[j-v[i+note]]+c[i+note]);
            out=max(dp[j],out);
        }
    }
    cout<<C-out;
    return 0;
}

但是事实上,这样的话我们会发现dp的时间复杂度过高,在第28组数据会导致超时。因此我们舍去转化的过程,直接求一个至少装至n的背包所负载的最小价值就可以了

#include<bits/stdc++.h>
#define maxn 5005
using namespace std;
inline char get(){
    static char buf[300000],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,300000,stdin),p1==p2)?EOF:*p1++; 
}
inline long long read(){
    register char c=get();register long long f=1,_=0;
    while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
    while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
    return _*f;
}
long long n;
long long t[maxn],c[maxn];
//?????????? 
long long V;
long long dp[4005];
int main(){
    //freopen("1.txt","r",stdin);
    n=read();
    long long out=1e18+1;
    for(register long long i=1;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=1,V=max(V,t[i]);
    V+=n;
    for(register int i=1;i<=V;i++)dp[i]=1e18+1;
    dp[0]=0;
    for(register int i=1;i<=n;i++){
        for(register int j=V;j>=t[i];j--){
            dp[j]=min(dp[j],dp[j-t[i]]+c[i]);
            if(j>=n)out=min(dp[j],out);
            //cout<<dp[j]<<endl;
        }
    }
    cout<<out;
    return 0;
}

转载于:https://www.cnblogs.com/Chen574118090/p/10209435.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值