DP练习——砝码称重
0.总结
Get to the key point firstly, the article comes from LawsonAbs!
- 不能呆板!不要认为dp只适合用于解决最大值,最小值类型的问题。在其计算最大最小值的同时,也保留了到达最值的过程,这个过程数据有时也是我们所需要的。
1.题意
给出质量分别为 1-n
的砝码各一个,求出由这n个砝码可称出的重量数。举例如下。
如果有3个砝码,即其重量分别是 1,2,3
,那么就可以称出6中不同的重量。分别是1,2,3,4,5,6
。
1 2 3
2.分析
2.1采用dp
数组f[i]=1
表示重量i可称达,否则表示不能称到重量i。
两重循环就可以计算出所有的可达重量i。
(其实如果不给这个算法冠上dp的帽子,可能大家就觉得不是那么难懂了。)稍微想一想,就知道这么做是符合逻辑而且是可以求出答案的。
2.2 算法步骤
- step 1. 第一重for循环,分别放上1-n个物品
- step 2.第二重
for
循环,从最大重量maxW
到0枚举,如果f[j-arr[i]]=1
,表示j-arr[i]
这个重量可达,于是站在j-arr[i]
的基础上,加上arr[i]
,j就可达了。所以f[j]=1。 - step 3.按照上面这个顺序类推,最后从1到maxW,找出f[i]=1的i的个数,就是最后的结果。
3.代码
#include<iostream>
using namespace std;
const int maxN = 20;
const int maxW = 1000;//限制最大可称重量
int n,m;//从n个数中选择m个
int arr[maxN];
int main(){
cin >> n;
//有重量为1,2,3,...n 的硬币各一枚
for(int i = 1;i <= n;i++){
arr[i] = i;
}
int f[maxW];
fill(f,f+maxW,0);
f[0] = 1;
//dp获取可称重的个数
for(int i = 1; i <= n;i++) {
for(int j = maxW;j >= 0;j--){
if(j >= arr[i] && f[j-arr[i]] == 1){//如果重量j大于砝码 arr[i]的重量
f[j] = 1;
}
}
}
int cnt = 0;
for(int i = 1;i<= maxW;i++){
if(f[i] == 1){
cnt ++;
}
}
cout << cnt <<"\n";
}