1. 程式人生 > 其它 >2755:神奇的口袋,考點:動規、揹包問題簡單版

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;
}