洛谷P2347 砝码称重 [2017年4月计划 动态规划01]
P2347 砝码称重
题目描述
设有1g、2g、3g、5g、10g、20g的砝码各若干枚(其总重<=1000),
输入输出格式
输入格式:输入方式:a1 a2 a3 a4 a5 a6
(表示1g砝码有a1个,2g砝码有a2个,…,20g砝码有a6个)
输出格式:输出方式:Total=N
(N表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)
输入输出样例
输入样例#1:
1 1 0 0 0 0
输出样例#1:
Total=3
暴力算法略,这里只讲dp。
背包问题,每个砝码选或不选,显然01背包。
我们把砝码按照从小到大的顺序依次排开
f[i][j]表示前i个砝码能否组成质量j。
转移:f[i][j] = f[i-1][j] || f[i-1][j-w[i]],w[i]表示第i件物品(砝码)的价值(质量),k为第i件物品(砝码)的数量
常规压缩一维:f[j] = f[j] || f[j-k*w[i]]
代码中做了这样的处理:用i和j来共同控制第i件物品。
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> inline int read() { int x = 0;char ch = getchar();char c = ch; while(ch > '9' || ch < '0')c = ch,ch = getchar(); while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0',ch = getchar(); if(c == '-')return -1 * x; return x; } const int INF = 99999999999; int sum; int w[7] = {0,1,2,3,5,10,20}; bool f[1010]; int num[10]; int ans; int main() { for(int i = 1;i <= 6;i ++) { num[i] = read(); sum += num[i] * w[i]; } f[0] = true; for(int i = 1;i <= 6;i ++) { for(int j = 1;j <= num[i];j ++) { for(int k = sum;k >= w[i];k --) { if(f[k - w[i]])f[k] = true; } } } for(int i = 1;i <= sum;i ++) { if(f[i])ans ++; } printf("Total=%d", ans); return 0; }