多重背包的二进制优化

多重背包的二进制优化

以一道题目举例:
来源:宁波工程学院2020年新生校赛

题目描述:

训练师小梁在一次机缘巧合中,发现了一个皮卡丘部落,她非常喜欢皮卡丘,但由于精灵球有限,所以她打算在这里逗留一段时间,部落中有n个皮卡丘,每个皮卡丘有不同的可爱度q[i],小梁要欣赏这些皮卡丘,但有的皮卡丘被看多了会抑郁,所以她要合理的分配时间和看的次数,收获最多的可爱度。

输入:

到达部落的时间s(英文的冒号),离开部落的时间e(英文的冒号),皮卡丘的个数n (s<=e,n<=10000) 下面n行
t,q,s,分别代表,欣赏这只皮卡丘需要的时间(分钟),这只皮卡丘的可爱度,这只皮卡丘最多能看几次(s=0表示这只皮卡丘脾气很好,能看无限次)。

输出:

能获取的最大可爱度。

样例输入:

5:30 7:10 5
3 1 5
4 4 2
2 1 0
4 5 3
5 6 0

样例输出:

120

代码:

#include <iostream>
using namespace std;
const int INF = 65535;
int n, m, n1;
int count;
int v[100001], w[100001];
int f[100001];
void read() {
    int a = 0, b = 0, c = 0, d = 0;
    int i;
	scanf("%d:%d%d:%d%d", &a, &b, &c, &d, &n);
    if (a == c) m = d - b;
    else if (a < c && b > d) m = (c - a - 1) * 60 + (d + 60 - b);
    else m = (c - a) * 60 + (d - b);
    for (i = 1; i <= n; i++) {
        int x, y, s, t = 1;
		scanf("%d%d%d", &x, &y, &s);
        if (s == 0) s = INF;   //如果是0,表示有无限件
		//二进制优化,总所周知,二进制可以用来表示任何数,比如10以内的数:
		//10 = 1 + 2 + 4 + 3, 这四个数字就可以用来表示10包括10以内的所有数字,比原来的10个数字少了6个
        while (s >= t) {
            v[++n1] = x * t;  //体积
            w[n1] = y * t;  //价值
            s -= t;
            t *= 2;
/*
循环过程:
0  s = 10, t = 1;
1  s = 9, t = 2;
2  s = 7, t = 4;
3  s = 3, t = 8;
*/
        }
//这一步是二进制没有补到的数,比如10 = 1 + 2 + 4 + 3,这一步就是加上3的部分
        v[++n1] = x * s;
        w[n1] = y * s;
    }
}
int main() {
    read();
	//01背包
    for (int i = 1; i <= n1; i++)
        for (int j = m; j >= v[i]; j--)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    cout << f[m] << endl;
    return 0;
}

代码中使用了二进制优化,关于多重背包的二进制优化还可以参考阎总的背包九讲专题,大概在56:00处:背包九讲专题

普通多重背包二进制优化模板:

#include <iostream>
using namespace std;
int n, n1, m;
int v[1001], w[1001], f[1001];
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        int x, y, s, t = 1;
        cin >> x >> y >> s;
        while (s >= t) {
            v[++n1] = t * x;
            w[n1] = t * y;
            s -= t;
            t *= 2;
        }
        v[++n1] = s * x;
        w[n1] = s * y;
    }
    for (int i = 1; i <= n1; i++)
        for (int j = m; j >= v[i]; j--)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    cout << f[m] << endl;
    return 0;
}
posted @ 2021-05-15 18:21  Dawnlight-_-  阅读(63)  评论(0编辑  收藏  举报