题解:逃亡的准备 以及 有限背包的二进制优化


目录
  • 题目
    • 【问题描述】
    • 【输入格式】
    • 【输出格式】
    • 【输入样例】
    • 【输出样例】
  • 解析
    • 什么是二进制优化呢?

题目

【问题描述】

  在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品。现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常感谢你。

【输入格式】

  第1行有2个整孰物品种数n和背包装载体积v;
  第2行到i+l行每行3个整数,为第i种物品的数量m、体积w、价值s。

【输出格式】

  仅包含一个整数,即为能拿到的最大的物品价值总和。

【输入样例】

  2 10
  3 4 3
  2 2 5

【输出样例】

  13

解析

这道题是一个有限背包,我们可以按照有限背包的板子写:

#include
using namespace std;
int n,v;
struct bag {
    int m,w,s;
} a[1000001];
int dp[1000001];
int main() {
    scanf("%d %d" ,&n ,&v);
    for(int i = 1; i <= n; i++) {
	    scanf("%d %d %d" ,&a[i].m,&a[i].w,&a[i].s);
    }
    for(int i = 1; i <= n; i++) {
	    for(int j = 1; j <= a[i].m; j++) {
		    for(int k = v; k >= a[i].w; k--) {
			    dp[k] = max(dp[k],dp[k - a[i].w] + a[i].s);
		    }
	    }
    }
    printf("%d" ,dp[v]);
    return 0;
}

但是这样做复杂度是有亿点点高的,高到可以卡掉三个点,所以我们需要用到二进制优化来帮我们降低复杂度:

什么是二进制优化呢?

顾名思义,我们把同种每2n的物品放在一起,当作一件物品(其价值和体积需要对应累加),处理完后当作0 1背包来做即可。
比如7个物品:
7 = 1 + 2 + 4.
而有意思的是,1,2,4正好可以凑出从1到7所有的整数,因此我们这么做在dp的时候是不会少情况的(具体证明我也不会)。
接下来就是二进制优化之后的代码:

#include
using namespace std;
int ans = 0,nn = 0,t;
int dp[2001]= { },j,w[100001],s[100001];
int a[100001],b[1000001];
int m[100001];
int n,v;
int cnt = 0;
int main() {
    scanf("%d %d" ,&n,&v);
    for(int i = 1;i <= n; i++){
	    scanf("%d %d %d" ,&m[i],&a[i],&b[i]);
    }
    for(int i = 1;i <= n; i++){
	    for(int j = 1;j <= m[i];j<<=1){
		    w[++cnt] = j * a[i];
		    s[cnt] = j * b[i];
		    m[i] = m[i] - j;
	    }
	    if(m[i] > 0){
		    s[++cnt] = m[i] * b[i];
		    w[cnt] = m[i] * a[i];
	    }
    }
    for(int i = 1; i <= cnt; i++) {
	    for(int k = v; k >= w[i]; k--) {
		    dp[k] = max(dp[k],dp[k - w[i]] + s[i]);   //处理完后所有的都要换成新数组
	    }
    }
    printf("%d" ,dp[v]);
        return 0;
}