题意
Bob的购物推车里有
n
n
n 个物品,每个物品的价格是
c
i
c_i
ci,会占用服务员
t
i
t_i
ti 的时间进行结账。Bob是个坏孩子,在服务员被某个物品占用的期间,他每秒都可以偷走一个东西。请问他最少花多少钱就可以拿走所有的东西(偷走也行)。
注意:偷一个东西需要的时间是
1
1
1 秒,一个东西占用服务员的时间是
t
i
t_i
ti 秒,别搞混了。
思路推导
什么?!偷一个东西和买一个东西的时间居然还不一样?完全糊涂了。只能找找他们之间的关系。记买的物品的编号集合为
M
M
M,则偷的物品就是剩下的
n
−
∣
M
∣
n-|M|
n−∣M∣ 个(这个像绝对值一样的符号是求集合中元素个数的意思)。由于推导过程较长,非蒟蒻只需要看三个不等式,忽略文字。
买
M
M
M 中的所有物品会占用服务员
∑
i
∈
M
t
i
\sum_{i \in M} \ t_i
∑i∈M ti 秒,偷剩下的东西要
n
−
∣
M
∣
n-|M|
n−∣M∣ 秒,显然,
n
−
∣
M
∣
≤
∑
i
∈
M
t
i
n-|M| \le \sum_{i \in M} \ t_i
n−∣M∣≤∑i∈M ti,因为服务员被占用的时候才能偷东西。移项后得
∑
i
∈
M
t
i
+
∣
M
∣
≥
n
\sum_{i \in M} \ t_i+|M| \ge n
∑i∈M ti+∣M∣≥n,不等号左边的式子是
∣
M
∣
|M|
∣M∣ 个
t
i
t_i
ti 相加后再加上
∣
M
∣
|M|
∣M∣,可以把
∣
M
∣
|M|
∣M∣ 放到
∑
\sum
∑ 里面,式子变成
∑
i
∈
M
(
t
i
+
1
)
≥
n
\sum_{i \in M} \ (t_i+1) \ge n
∑i∈M (ti+1)≥n。
看不懂的别慌,我还有一种解释:对于每一个花钱购买的物品,Bob不仅可以获得这个物品本身,还可以偷走
t
i
t_i
ti个物品。也就是说,买一个物品
i
i
i,可以拿走
t
i
+
1
t_i+1
ti+1个物品,由于所有物品都要拿走,就得到了上面的最后一个不等式。
转化为01背包
这是一个变形的01背包,由上面推导可知,若
t
i
+
1
t_i+1
ti+1是每个物品的体积,需要保证体积之和
≥
n
≥n
≥n,
c
i
c_i
ci显然就是每个物品的价值,只不过这里要少花钱,价值之和要尽量小。
(↑我打公式太累了)具体详见代码。
代码护送
#include<bits/stdc++.h>
using namespace std;
int n,t[2005],c[2005],maxx;
long long f[2005][4005],ans=0x3f3f3f3f3f3f3f3f;
//一定要开long long,ans的初始值也要设为0x3f3f3f3f3f3f3f3f
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>t[i]>>c[i];
t[i]++;//转化成普通01背包,需要加1
maxx=max(maxx,t[i]);
}
memset(f,0x3f,sizeof(f));//因为要算最小值,初始值莫忘
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<n+maxx;j++){//从0开始继承上一层的值,j<t[i]也要继承
f[i][j]=f[i-1][j];
if(j>=t[i]) f[i][j]=min(f[i][j],f[i-1][j-t[i]]+c[i]);
}
for(int i=n;i<n+maxx;i++) ans=min(ans,f[n][i]);
cout<<ans<<endl;
return 0;
}
看懂了的留个赞呗(doge