动态规划简单题

题干如下:

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

输入:

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

输出:

  • 一个数字,表示不同的选择物品的方式的数目。

样例输入:

1
2
3
4
3
20
20
20

样例输出:

1
3

递归法

1
2
3
4
5
6
7
int a[25]; //存放各物品体积
int Ways(int w,int obj){
if(w==0) return 1;
if(obj <= 0) return 0;
return Ways[w][obj-1] + Ways[w-a[obj]][obj-1];
}
//只需调用Ways(40,n)即可

由上不难得出状态转移方程为:

1
Ways[i][j] = Ways[i][j-1] + Ways[i-a[j]][j-1];

递推(动态规划)解法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
#include<algorithm>
using namespace std;

int n;
int objects[25];
int Ways[45][25];
int main(){
cin >> n;
for(int i=1;i<=n;i++){
cin >> objects[i];
Ways[0][i] = 1;
}
Ways[0][0] = 1;
for (int i = 1; i <= 40; ++i){
for(int j = 1; j <= n; ++j){
Ways[i][j] = Ways[i][j-1];
if(i - objects[j] >= 0)
Ways[i][j] += Ways[i-objects[j]][j-1];
}
}
cout << Ways[40][n] << endl; //Prints:3
return 0;
}

时间复杂度: O(v*n)