题目地址:
https://www.luogu.com.cn/problem/P2347
题目描述:
设有
1
g
1\mathrm{g}
1g、
2
g
2\mathrm{g}
2g、
3
g
3\mathrm{g}
3g、
5
g
5\mathrm{g}
5g、
10
g
10\mathrm{g}
10g、
20
g
20\mathrm{g}
20g的砝码各若干枚(其总重
≤
1000
\le 1000
≤1000),可以表示成多少种重量?
输入格式:
输入方式:
a
1
,
a
2
,
a
3
,
a
4
,
a
5
,
a
6
a_1 , a_2 ,a_3 , a_4 , a_5 ,a_6
a1,a2,a3,a4,a5,a6
(表示
1
g
1\mathrm{g}
1g 砝码有
a
1
a_1
a1个,
2
g
2\mathrm{g}
2g砝码有
a
2
a_2
a2个,…,
20
g
20\mathrm{g}
20g砝码有
a
6
a_6
a6个)
输出格式:
输出方式:Total=N
(
N
N
N 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)
背包问题。可以将所有砝码编个号。设 f [ k ] [ s ] f[k][s] f[k][s]为只用前 k k k个砝码,能否称出 s s s的重量,那么 f [ k ] [ s ] = f [ k − 1 ] [ s ] ∨ f [ k − 1 ] [ s − w [ k ] ] f[k][s]=f[k-1][s]\lor f[k-1][s-w[k]] f[k][s]=f[k−1][s]∨f[k−1][s−w[k]]其中 w [ k ] w[k] w[k]为第 k k k个砝码的重量。可以考虑优化为 1 1 1维,其实就是 0 − 1 0-1 0−1背包。代码如下:
#include <iostream>
using namespace std;
const int N = 1010;
int a[10], w[] = {1, 2, 3, 5, 10, 20};
bool f[N];
int main() {
for (int i = 0; i < 6; i++)
scanf("%d", &a[i]);
f[0] = true;
for (int i = 0; i < 6; i++)
for (int j = 1; j <= a[i]; j++)
for (int k = 1000; k >= w[i]; k--)
f[k] |= f[k - w[i]];
int res = 0;
for (int i = 1; i <= 1000; i++) if (f[i]) res++;
printf("Total=%d\n", res);
}
时间复杂度 O ( W ∑ i a i ) O(W\sum_i a_i) O(W∑iai),空间 O ( W ) O(W) O(W), W = 1000 W=1000 W=1000。