【题目来源】AcWing 5. 多重背包问题 II
【题意分析】根据当前数据范围,
O
(
n
3
)
O(n^3)
O(n3) 的时间复杂度过不了,最多为
O
(
n
2
l
o
g
n
)
O(n^2logn)
O(n2logn)。
【优化方法】
二进制优化
0
/
1
0/1
0/1 背包部分:
对于当前
0
/
1
0/1
0/1 背包部分,我们用
k
k
k 个物品来表示装入
1
1
1 ~
k
k
k 个物品的情况,比如;
有一个物品有
15
15
15 个,且符合
0
/
1
0/1
0/1 背包,那么我们需要循环
15
15
15 次,即:
但是可以计算
15
15
15 以内有哪些
2
2
2 的幂次方数:
此时出现了
3
3
3 个
2
2
2 的幂次方数,
2
2
2,
4
4
4,
8
8
8,剩余
1
1
1,那么
1
1
1,
2
2
2,
4
4
4,
8
8
8 这四个数可以组成
0
0
0 ~
15
15
15 的任意一种情况:
因此,可以通过下图来理解该方法对时间复杂度的优化方法:
从对
15
15
15 个物品做
0
/
1
0/1
0/1 背包优化为了给
4
4
4 个物品做
0
/
1
0/1
0/1 背包,
O
(
n
)
O(n)
O(n)优化为了
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)
整个算法
O
(
n
3
)
O(n^3)
O(n3) 优化为了
O
(
n
2
l
o
g
n
)
=
1000
∗
l
o
g
2
2000
∗
2000
≈
1000
∗
11
∗
2000
=
2.2
∗
1
0
7
O(n^2logn) = 1000 * log_22000*2000 ≈ 1000 * 11 * 2000 = 2.2 * 10^7
O(n2logn)=1000∗log22000∗2000≈1000∗11∗2000=2.2∗107,
1000
m
s
1000ms
1000ms 能过,代码如下:
#include<iostream>
using namespace std;
struct node{
int v, w;
} q[2000050];
int n, m, V, dp[2050], a, b, c;
int main(){
cin >> n >> V;
for(int i = 1; i <= n; i ++){
cin >> a >> b >> c;
//关键代码:begin
int k = 1;
while(k <= c){
m ++;
q[m].v = k * a;
q[m].w = k * b;
c -= k;
k *= 2;
}
if(c > 0){
m ++;
q[m].v = c * a;
q[m].w = c * b;
}
//关键代码:end
}
for(int i = 1; i <= m; i ++)
for(int j = V; j >= q[i].v; j --)
dp[j] = max(dp[j], dp[j - q[i].v] + q[i].w);
cout << dp[V];
return 0;
}