【问题标题】:A Dynamic Programming problem in USACOUSACO 中的动态规划问题
【发布时间】:2011-07-11 15:58:59
【问题描述】:

在第2.2节中,一个叫做“子集和”的问题要求你计算一个从1到n的整数集有多少种方式可以划分为两个总和相同的集。

我知道复发是:

f[i][j] : j 与 1...i 相加的方式数

f[i][j]=f[i-1][j]+f[i-1][j-i]

如果初始条件是:

f[1][1]=1;//其他都为零,主循环从2开始

或者:

f[0][0]=1;//其他都为零,主循环从1开始

答案都是f[n][n*(n+1)/4]。这是否意味着初始条件不影响答案?

但是如果我使用一维数组,比如 f[N]:

设 f[0]=1,从 1 开始循环(所以 f[0] 实际上是 f[0][0]),答案是 f[n]/2

或者f[1]=1,从2循环(f[1]是f[1][1]),答案是f[n]

我很困惑……

【问题讨论】:

    标签: dynamic-programming


    【解决方案1】:

    我不知道你是否仍然被这个问题所困扰,但这里有一个解决方案,供遇到此问题的其他人使用。

    让ways[i] 是使用数字 1...N 的子集获得 i 总和的方式数。

    那么就变成了0-1背包算法的变种:

    基本情况:方式[0] = 1

    for (int i = 1; i <= N; i++) {
        for (int j = sum - i; j >= 0; --j) { //sum is n*(n+1)/2
            ways[j + i] += ways[j];
        }
    }
    

    您的答案位于ways[sum/2]/2。

    【讨论】:

    • 只有当 sum 为偶数时才应计算此 DP。如果它很奇怪,你可以返回 0。
    • 嗨,我读了你的答案,但我似乎不明白为什么ways[sum/2]/2 是答案。如果你不介意,你能给我解释一下吗?
    • 嘿,据我了解,它的方式[i]表示您可以获得i总和的方式数。对于要等分的子集,每组所需的总和为 sum/2。最终答案必须除以 2,因为一个分区有助于 2 个集合。
    猜你喜欢
    • 1970-01-01
    • 2011-10-17
    • 2012-10-25
    • 2012-04-09
    • 2011-10-14
    • 1970-01-01
    • 2021-02-25
    相关资源
    最近更新 更多