Bob 来到一个现金便利店,放置了 n 件商品到他的手推车,然后前往收银台付款。每件商品用两个属性描述:价格 ci,时间 ti
(收银员花在这件商品上的时间,以秒计)。当收银员被某件商品占用时间之时,Bob 可以从手推车窃取一些其他商品。Bob 恰好需要 1
秒钟,才能窃取一件商品。请问,Bob 必须最少支付多少钱给收银员?注意:商品递给收银员的顺序,由 Bob 决定。输入 第一行包含了数 n (1 ≤ n ≤ 2000)。接下来的 n 行,每行描述了一件商品,使用两个数 ti, ci
(0 ≤ ti ≤ 2000, 1 ≤ ci ≤ 109)。如果 ti 等于 0 ,那么 Bob 无法在收银员被商品 i
占用的时间窃取任何东西。输出 输出一个数 — 问题的答案:Bob 必须支付的最少金额。
示例
输入
4
2 10
0 20
1 5
1 3
输出
8
输入
3
0 1
0 10
0 100
输出
111
思路
-
题意:Bob准备买n个物品,每个物品有 价格c,占用收银员时间t两个属性,当收银云某个物品用 t秒时,Bob可以在这期间每一秒偷一个物品,问买下这些物品的最小花费是多少?
-
分析
一个巧妙的转化,因为Bob可以一秒中偷一个物品,那么当他买一个物品之后,他就可以偷t[i]个物品
那么他总共可以获得t[i] + 1 件物品,我们可以把t[i]+1 当作第i件物品的体积,而c[i] 就是i这件物品的花费
这样当总共要获得n件物品(通过买 + 偷 来实现)就相当于背包的总空间为n,
这个时候就把题目转化成了 背包空间为n,要买n件物品,每件物的价值为 c[i] 、体积为t[i] + 1 的01背包,那么要求的问题就转化为了背包能够装下的最小价值
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int mxn = 2005;
ll dp[mxn]; //dp[j] 装满背包空间为j时所需要的最小花费,注意每件物品的空间我们认为是1,因为 一秒钟偷一个的原因
ll t[mxn], c[mxn];
/* 思路:一个巧妙的转化,因为Bob可以一秒中偷一个物品,那么当他买一个物品之后,他就可以偷t[i]个物品
* 那么他总共可以获得t[i] + 1 件物品,我们可以把t[i]+1 当作第i件物品的体积,而c[i] 就是i这件物品的花费
* 这样当总共要获得n件物品(通过买 + 偷 来实现)就相当于背包的总空间为n,
* 这个时候就把题目转化成了 背包空间为n,要买n件物品,每件物的价格为 c[i] 的01背包,那么自然我们要求的是背包能够装下的最小花费了
*/
int main()
{
/* freopen("A.txt", "r", stdin); */
/* freopen("Ans.txt", "w", stdout); */
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%lld %lld", &t[i], &c[i]), t[i] ++;
memset(dp, INF, sizeof(dp)); //让求最小的花费所以,初始化为INF
dp[0] = 0;
for(int i = 1; i <= n; i ++)
{
int j;
for(j = n; j >= t[i]; j --)
dp[j] = min(dp[j], dp[j - t[i]] + c[i]);
for( ; j > 0; j --) //这个时候 j < t[i] 也就是说,如果买了第i件物品那么剩下的j物品都可被偷完了(前提是 c[i] < dp[j])
dp[j] = min(dp[j], c[i]);
}
printf("%lld\n", dp[n]);
return 0;
}