题意 :

以下两个问题的物品都只能取有且只有一次

① 给你 N 个物品,所有物品的价值总和不会超过 5000, 单个物品的价格就可达 10^10 ,背包容量为 B 

② 给你 N (N ≤ 40 ) 个物品,物品的单个价值和重量都达到 10^15 问你在背包容量为 W 

给出 ① 和 ② 问题条件下背包所能装出来的最大价值

 

分析 :

① 因为单个物品的价值实在太大,如果仍然按照普通 0/1 背包的 dp 定义方法数组是开不下的

但是发现价值的总和并不大,所以从价值这里下手,定义 dp[i][j] = 从 1 ~ i 个物品背包价值为 j 时的最小重量

dp 的状态转移方程效仿普通的 0/1 背包即可,但是是取最小 dp[i][j] = min(dp[i][j], dp[i-1][j-v[i]] + w[i])

同样可以使用 0/1 背包的空间优化将 dp 数组转化为一维的来减少空间复杂度

以下是  FZU 2214 的 AC 代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn = 5e3 + 10;
const LL INF = 0x3f3f3f3f;
LL dp[maxn], w[555], B;
int v[555];
int N, C;

int main(void)
{
    int nCase;
    scanf("%d", &nCase);
    while(nCase--){
        scanf("%d %lld", &N, &B);
        C = 0;
        for(int i=1; i<=N; i++)
            scanf("%lld %lld", &w[i], &v[i]),
            C += v[i]; /// C 累加的是所有物品的价值总和

        for(int j=0; j<=C; j++)
            dp[j] = INF;/// 初始化 dp 数组应当赋予一个较大的数
        dp[0] = 0;

        for(int i=1; i<=N; i++)
            for(int j=C; j>=v[i]; j--)
                dp[j] = min(dp[j], dp[j-v[i]]+w[i]);

        for(int j=C; j>=0; j--){
            if(dp[j] <= B){///从大到小遍历价值,第一个满足条件的 dp 数组值的下标便是答案
                printf("%d\n", j);
                break;
            }
        }
    }
    return 0;
}
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-10-26
  • 2021-06-16
  • 2021-07-22
  • 2022-12-23
  • 2022-02-16
  • 2021-12-18
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-09-19
  • 2021-12-14
相关资源
相似解决方案