【问题描述】
你有一架天平和N 个砝码,这N 个砝码重量依次是W1, W2…WN。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。
样例:
input:
3
1 4 6
output:
10
就是一个动态规划,每次状态转移dp[ i ][ j ] 表示加上第i个砝码 j 重量是否可以被称出,也就是当前用了1 到 i 种砝码。
sum+= a[i];//先算出总和,作为j的右边界
dp结构:
for(i = 1;i <= n;i++)
{
for(j = 1;j <= sum;j++)
{
dp[i][j] = dp[i-1][j];//使用i-1个砝码可以得到的j,使用i个砝码也可以得到
if(!dp[i][j])
{
if(j < a[i]) //如果j小于本砝码质量
dp[i][j] = dp[i-1][a[i]-j];//放在另一边得出差值,如果本侧存在a[i]-j,可以相减得出j
if(j == a[i])
dp[i][j] = 1;
if(j > a[i])//j大于当前砝码质量
dp[i][j] = dp[i-1][j-a[i]];//如果本侧j-a[i]存在,那么j就可以由a[i]+(j-a[i])得出
}
}
}
n个砝码是否可以拼出j
for(j = 1;j <= sum;j++) if(dp[n][j]) ans++;
#include <bits/stdc++.h>
using namespace std;
const long long inf = 0x7fffffffffffffff;
bool dp[106][100006];
int a[106];
int main()
{
int i,j,n,sum = 0;
scanf("%d",&n);
for(i = 1;i <= n;i++){
scanf("%d",&a[i]);
sum+= a[i];
}
for(i = 1;i <= n;i++){
for(j = 1;j <= sum;j++){
dp[i][j] = dp[i-1][j];
if(!dp[i][j]){
if(j < a[i]) dp[i][j] = dp[i-1][a[i]-j];
if(j == a[i]) dp[i][j] = 1;
if(j > a[i]) dp[i][j] = dp[i-1][j-a[i]];
}
}
}
long long ans = 0;
for(j = 1;j <= sum;j++) if(dp[n][j]) ans++;
printf("%lld",ans);
return 0;
}