洛谷P2347 砝码称重 [2017年4月计划 动态规划01]

时间:2022-12-31 15:47:52

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;
}