B - Checkout Assistant CodeForces - 19B(01背包变形)

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;
}

猜你喜欢

转载自www.cnblogs.com/lql-nyist/p/12687634.html
今日推荐