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可以每过一秒钟顺走一件商品。所以我们转化一下,在第i件物品的时候,我们花费了Ci的价格买走了Ti+1件商品。所以我们把Ti+1看成第i件物品的体积,然后价值是Ci,这样的话就转化成01背包的问题了,问题就可以变成n件物品,从中选出若干件使得其体积不小于n且总价值最小的问题,然后用01背包就可以求解了。
AC代码:
#include <stdio.h>
#include <string>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <stack>
#include <vector>
typedef long long ll;
const int maxx=1000010;
const int inf=0x3f3f3f3f;
const int mod=10007;
using namespace std;
ll c[maxx],t[maxx];
ll dp[maxx];
int main()
{
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));
dp[0]=0;
for(int i=1; i<=n; i++)
{
for(int j=n; j>=t[i]; j--)
dp[j]=min(dp[j],dp[j-t[i]]+c[i]);
for(int j=t[i]-1; j>=0; j--)
dp[j]=min(dp[j],c[i]);
}
printf("%lld\n",dp[n]);
return 0;
}