深圳幻海软件技术有限公司 欢迎您!

砝码称重问题

2023-04-19

砝码称重问题描述你有一架天平和N个砝码,这N个砝码重量依次是W1,W2,⋅⋅⋅,WN。请你计算一共可以称出多少种不同的正整数重量?注意砝码可以放在天平两边。输入格式输入的第一行包含一个整数N。第二行包含N个整数:W1,W2,W3,⋅⋅⋅,WN。输出格式输出一个整数代表答案。数据范围对于50%的评测用

砝码称重

问题描述

你有一架天平和 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

样例解释

能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;

2 = 6 − 4 (天平一边放 6,另一边放 4);

3 = 4 − 1;

4 = 4;

5 = 6 − 1;

6 = 6;

7 = 1 + 6;

9 = 4 + 6 − 1;

10 = 4 + 6;

11 = 1 + 4 + 6。


题解

这里使用闫式dp分析法,将分析过程分为状态表示和状态计算两个过程

状态表示

集合:
只考虑前i个物品,能得出的j种方案的集合

属性:
是否为空

这里属性也可设置为数量,设置为数量也更好理解些,至于为什么用bool来进行判断,后面会进行解释


状态计算

我们可以将f(i,j)集合分为三个子集,第一个为不选i个物品,第二个为左边选i个物品,第三个为右边选i个物品

所得状态方程如下:

不选:

f[i - 1][j]
  • 1

左边:

f[i - 1][abs(j - w[i])]
  • 1

右边:

f[i - 1][j + w[i]]
  • 1

选左边的方程由实际含义可得知 f[i][j - w[i]] = f[i][w[i] - j] = f[i][ abs([j] - w[i]) ] 故可以利用取绝对值避免数组下标为负数的情况。


状态转移方程

从上可以得到我们的状态转移方程为

f[i][j] = f[i - 1][j] || f[i - 1][j + w[i]] || f[i - 1][abs(j - w[i])]
  • 1

判断前i个数不选或选左右边后得到的值,如果j对第i个数的权值w[i]进行选择后能与 上一个数i-1进行选择后 的值进行匹配,则该j值为true

如果我们将状态表示的属性设为数量,那么此处的状态转移方程应为:

f[i][j] = f[i - 1][j] + f[i - 1][j + w[i]] + f[i - 1][abs(j - w[i])]
  • 1

这样到最后其实我们也是判断 选前i个值第j个值是否为0,那么我们不如从一开始就将属性设为bool值,只要不选,和选左右边这三个状态有一个状态是合法的状态,那么f[i][j]就是合法的,即为true


详细代码(C++)

#include <iostream>

using namespace std;
const int N = 110, M = 2e5 + 10;    //假设sum=1e5,加上w[i]是会大于1e5的,故取2e5+10较妥当
int n,sum,w[N];
int f[N][M];

int main()
{
    cin >> n;
    for (int i = 1;i <= n; i++)
    {
        cin >> w[i];
        sum += w[i];
    }
    f[0][0] = true;     
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j <= sum; j++)
        {
            f[i][j] = f[i - 1][j] || f[i - 1][j + w[i]] || f[i - 1][abs(j - w[i])];
        }
    }
    int ans = 0;
    for(int i = 1; i <= sum; i++)   //0不作为选取方案,故从1开始遍历
    {
        if(f[n][i]) ans++;
    }
    cout << ans;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览44435 人正在系统学习中