2755:神奇的口袋,考点:动规、背包问题简单版

原题:http://bailian.openjudge.cn/practice/2755/

描述

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

输入

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

输出

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

样例输入

3
20
20
20

样例输出

3 

解法

思路:动态规划重要的题!!!

dp[i][j]:考虑前i种,凑出的体积为j时选择物品的方式数目

边界条件:

dp[i][0]=1;dp[0][a[0]]=1(在第一个东西能装进去的前提下)

然后就可以从上往下进行计算了,

dp[i][j]先等于dp[i-1][j](不放进去),如果j可以让它放进去,就加上放进去的种数dp[i-1][j-a[i]]

自己写的代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[25][41];//dp[i][j]表示考虑前i种,可用体积为j的时候不同的选择物品的方式数目
int a[25];
int main()
{
    memset(dp, 0, sizeof(dp));
    memset(a, 0, sizeof(a));
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n; i++)
        dp[i][0] = 1;
    if(a[0]<=40)
        dp[0][a[0]] = 1;
    for (int i = 1; i < n; i++) {
        for (int j = 1; j <= 40; j++) {
            dp[i][j] = dp[i - 1][j];
            if (j >= a[i])
                dp[i][j] += dp[i - 1][j - a[i]];
        }
    }
    cout << dp[n - 1][40] << endl;
    return 0;
}

种数、体积哪个做第一维变量都可以,如果是体积做第一维变量:

#include <iostream>
using namespace std;
int a[40]; int N;
int Ways[50][40];//Ways[i][j]表示从前j种物品里凑出体积i的方法数
int main() {
    cin >> N;
    memset(Ways, 0, sizeof(Ways));
    for (int i = 1; i <= N; ++i) {
        cin >> a[i];  Ways[0][i] = 1;
    }
    Ways[0][0] = 1;
    for (int w = 1; w <= 40; ++w) {
        for (int k = 1; k <= N; ++k) {
            Ways[w][k] = Ways[w][k - 1];
            if (w - a[k] >= 0)
                Ways[w][k] += Ways[w - a[k]][k - 1];
        }
    }
    cout << Ways[40][N];
    return 0;
}

还可以用我为人人型动规节省空间。int sum,判断sum[40]可达了几次。

#include <iostream>
using namespace std;
#define MAX 41
int main() {
    int n, i, j, input; int sum[MAX];
    for (i = 0; i < MAX; i++) sum[i] = 0;
    cin >> n;
    for (i = 0; i < n; i++) {
        cin >> input;
        for (j = 40; j >= 1; j--)
            if (sum[j] > 0 && j + input <= 40)
                sum[j + input] += sum[j]; // 如果j有sum[j]种方式可达,则每种方式加上input就可达 j + input
            sum[input]++;
    }
    cout << sum[40] << endl;
    return 0;
}

 

上一篇:从pbf文件读取数据使用networkx 计算最短路径


下一篇:Unit1 Finding ways to listen to Music