CodeForces 19B Checkout Assistant (背包)

来源:互联网 发布:java中线程安全的类 编辑:程序博客网 时间:2024/06/04 22:57
题目类型  背包   | 对背包问题不了解的同学 猛戳 -> 背包九讲

题目意思
给出 n 件物品(1 <= n <= 2000)
每件物品有两个属性 Ti Ci (Ti 的意思是如果你取这件物品的话可以免费取其他的 Ti件物品 Ci的意思是如果你取这件物品需要花费Ci)
问 把 n 件物品取完需要的最少花费是多少

解题方法
dp[i][j] -> 取完前 i 件物品后还可以免费取 j 件物品的最小花费
状态转移 
不取第i件物品 dp[i][j-1] = min(dp[i][j-1], dp[i-1][j]  (因为取完前i-1个物品后如果还可以免费取其他j个物品的话 就可以把第i个物品取了变                                                         成dp[i][j-1])
 取第i件物品  dp[i][j+第i件物品可以提供的免费数] = min(dp[i][j+第i件物品可以提供的免费数], dp[i-1][j] + 第i件物品所需的花费)
递推即可

注意
j的下标可能是负数 所以可以所有下标向右移若干位

参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int MAXN = 2000 + 10;typedef long long LL;const LL INF = ((LL)1)<<62;const int add = 2000;int a[MAXN][2];LL dp[MAXN][MAXN*2];int main() {  int n;  while(scanf("%d", &n) != EOF) {    for( int i=0; i<n; i++ ) {      scanf("%d%d", &a[i][0], &a[i][1]);    }    for( int i=0; i<n; i++ ) for( int j=0; j<=4000; j++ ) dp[i][j] = INF;    dp[0][a[0][0]+add] = a[0][1];    dp[0][-1+add] = 0; //不选这件物品的话就意味着 取了这件物品还可以免费取 -1 件其他物品 加上add为了使下标不是负数,所有下标整体右移    for( int i=1; i<n; i++ ) {      for( int j=0; j<=4000; j++ ) {        if(j>0) dp[i][j-1] = min(dp[i][j-1], dp[i-1][j]);        if(j+a[i][0]<=4000) dp[i][j+a[i][0]] = min(dp[i][j+a[i][0]], dp[i-1][j] + a[i][1]);      }    }    LL res = INF;    for( int i=add; i<=4000; i++ ) res = min(res, dp[n-1][i]); //从add开始即从0开始, 表示取完了n件物品后(下标从0开始所以是n-1)    cout<<res<<endl;                                          //还可以取其他至少0件物品的最小值, 因为dp数组的第二维非负才有实际意义  }  return 0;}


0 0
原创粉丝点击