砝码称重
题目描述
你有一架天平和N 个砝码,这N 个砝码重量依次是W1, W2, ... , WN。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数N。
第二行包含N 个整数:W1, W2, W3, ... , WN。
对于50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过100000。
输出格式
输出一个整数代表答案。
输入样例
3
1 4 6
输出样例
10
动态规划
设置状态:
dp[i][j]
表示前 i 个砝码能否称出 j 的重量,1为能,0为不能
状态方程:
dp[i][j] = max(dp[i-1][j],max(dp[i-1][j+w[i]],dp[i-1][abs(j-w[i])]));
解析:
dp[i-1][j]
// 前i - 1个砝码能称出 j 的重量
dp[i-1][j+w[i]]
// 若前i - 1个砝码能称出j + w[i]的重量,则为第i个砝码放在称物品的一侧
dp[i-1][abs(j-w[i])]
// 若前i - 1个砝码能称出abs(j - w[i])的重量,则为第i个砝码放在称物品的另外一侧(使用abs函数是因为差值可能为负)
以上三种情况至少其中一个为1则dp[i][j] == 1
,若全部为0则 dp[i][j] == 0
#include <iostream>
#include <math.h>
using namespace std;
int dp[101][100001] = {0};
int n,sum,ans;
int main()
{
cin >> n;
int w[n+1];
for(int i = 1;i <= n;i++)
{
cin >> w[i];
sum += w[i]; // 总重
}
dp[0][0] = 1; // 初始状态
for(int i = 1;i <= n;i++)
{
for(int j = 0;j <= sum;j++)
{
dp[i][j] = max(dp[i-1][j],max(dp[i-1][j+w[i]],dp[i-1][abs(j-w[i])]));
}
}
for(int i = 1;i <= sum;i++)
{
if(dp[n][i])
{
ans++;
}
}
cout << ans;
return 0;
}