[NOIP1996 提高组] 砝码称重
题目描述
设有 、、、、、 的砝码各若干枚(其总重 ),可以表示成多少种重量?
输入格式
输入方式:
(表示 砝码有 个, 砝码有 个,, 砝码有 个)
输出格式
输出方式:Total=N
( 表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)
样例 #1
样例输入 #1
1 1 0 0 0 0
样例输出 #1
Total=3
提示
【题目来源】
NOIP 1996 提高组第四题
思路
首先定义一个位集dp,大小为 ,其中 ,并将其所有位重置为0。位集dp用于存储能够称出的重量,如果某个重量能被称出,那么对应的位就被设置为1。
然后从输入中读取砝码的数量,存储在数组a中。
接下来,将dp[0]设置为1,表示0克的重量可以被称出(即不使用任何砝码)。
之后,进行三层循环。外层循环遍历所有的砝码种类,中层循环遍历每种砝码的数量,内层循环遍历从1000克到0克的所有重量。在内层循环中,如果某个重量k可以被称出(即dp[k]为1),那么重量k+W[i]也可以被称出,其中W[i]是砝码的重量。因此,将dp[k+W[i]]设置为1。
最后,将dp[0]设置为0,表示不包括一个砝码也不用的情况,然后输出能够称出的重量的数量,即dp中值为1的位的数量。
注意
因为是01背包问题,一枚砝码只能使用一次,所以k要从1000到0遍历,否则会重复使用同一枚砝码。
AC代码
#include <algorithm>
#include <bitset>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;
const int N = 1e3 + 7;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
const int W[6] = {1, 2, 3, 5, 10, 20};
int a[6];
bitset<N> dp;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
dp.reset();
for (int i = 0; i < 6; i++) {
cin >> a[i];
}
dp[0] = 1;
for (int i = 0; i < 6; i++) {
for (int j = 1; j <= a[i]; j++) {
for (int k = 1000; k >= 0; k--) {
dp[k + W[i]] = dp[k];
}
}
}
// for (int i = 1; i <= 1000; i++) {
// if (dp[i]) {
// cout << i << "\n";
// }
// }
dp[0] = 0;
cout << "Total=" << dp.count() << "\n";
return 0;
}