动态规划之神奇的口袋

动态规划之神奇的口袋

题目

有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。
John现在有n(1≤n ≤ 20)个想要得到的物品,每个物品的体积分别是a1, a2……an。 John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋, John就可以得到这些物品。现在的问题是, John有多少种不同的选择物品的方式。

输入
输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1, a2……an的值。

输出
输出不同的选择物品的方式的数目。

输入样例
3
20
20
20

输出样例
3

解析

设C[n][h]为n个物品可以选出重量h的方式数目。ai为第i个物品的重量。那么C[k][m]表示前k个物品可以选出重量m的方式数目,那么我们可以考虑有没有必要选第k个物品:

一方面,如果必须选择第k个物品,那么也就意味着“第K个物品是组成重量为m所必须的”。换句话说,拿了第k个物品组成重量m的方式数目与不拿第k个物品所组成重量为m-a[k]的方式的数目是一样的。此时C[k][m] = C[k-1][m-a[k]]。

另一方面,如果不必选择第k个物品,也就意味着第k个物品的重量对于组成m重量没有任何贡献,那么不要它也是一样的,此时C[k][m] = C[k-1][m]。

所以结合两反面考虑,有如下递归公式:
C[k][m] = C[k-1][m-a[k]] + C[k-1][m]

这种思路的本质实际上是枚举出对每一个物品而言,要与不要对于整体的作用。题目上说物品数目的范围是1到20,所以总共有2^20中情况。其中有一些情况实际上是很不必要的,我们可以筛选一下,缩小范围,专业术语叫做“剪枝”。这里用动态规划写出优化后的代码。

解法一:递归

时间复杂度为O(2^n)。

#include <stdio.h>
int a[21];

int Pocket(int k, int m)
{
    if (m == 0)
    {
        return 1;   //要凑够重量为0,只有一种方式:什么都不选
    }
    if (k <= 0)
    {
        return 0;   //当没有物品时,可选方案为0,巧妇难成无米之炊
    }
    return Pocket(k-1, m-a[k]) + Pocket(k-1, m);    //Pocket(k-1, m-a[k])为必须要第k个物品时可选方案数
                                                    //Pocket(k-1, m)为不必要第k个物品时可选方案数
}

int main()
{
    int n;
    int i = 0;
    scanf("%d", &n);
    for (i = 1; i<=n; i++)
    {
        scanf("%d", &a[i]);
    }
    printf("%d\n", Pocket(n, 40));

    return 0;
}

解法二:递推(动规)

将递归化为递推,时间复杂度降为O(N*H)。

#include<stdio.h>

#define H 40
int N;
int a[21];
int ways[21][H];

int Pocket()
{
    int k = 0;
    int m = 0;
    for (k = 1; k <= N; k++)
    {
        for (m = 0; m <= H; m++)
        {
            int x = 0;
            ways[k][m] = ways[k-1][m];
            x = m - a[k];
            if (x >=0)
            {
                ways[k][m] += ways[k-1][x];
            }
        }
    }
    return ways[N][H];
}

int main()
{
    int i = 0;
    scanf("%d", &N);
    for (i = 1; i<=N; i++)
    {
        scanf("%d", &a[i]);
        ways[i][0] = 1;
    }
    ways[0][0] = 1;
    printf("%d\n", Pocket());
}

猜你喜欢

转载自blog.csdn.net/neverwa/article/details/79873581
今日推荐