[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