-
总Time Limit:
- 10000ms Memory Limit:
- 65536kB
-
Description
- 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。 Input
- 输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。 Output
- 输出不同的选择物品的方式的数目。 Sample Input
-
3 20 20 20
Sample Output -
3
这个题有点像背包的思想;
要求可以满足要求的次数;样例是1 3 ;2 3 ; 1 2 ;三种刚好满足40;
讨论状态 (选 或者 不选) ;
针对DP[i][j] 就为满足重量i选择的前j种商品的方法;
所以初始状态 dp[0][j] ( j>=0&&j<=n) == 1 ; (每个商品都考虑不选,则都有1种);
所以如果上个状态不选择j物品, 则 dp[i][j] = dp[i][j-1];
如果满足 i - a[j] >= 0 , 就选择这个物品 , 则有当前状态的选择次数+上个状态选择的次数;dp[i][j] += dp[i-a[j][j-1] ;
AC代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int a[30];
int n;
int dp[40][30];//dp[i][j]表示从前j种物品里凑出体积i的方法数
int main() {
cin >> n;
memset(dp,0,sizeof(dp));
for( int i = 1; i <= n;i++ )
{
cin >> a[i];
dp[0][i] = 1;
}
dp[0][0] = 1;
for( int i = 1 ; i <= 40; i++ )
{
for( int j = 1; j <= n; j++ )
{
dp[i][j] = dp[i][j-1];
if( i-a[j] >= 0)
dp[i][j] += dp[i-a[j]][j-1];
}
}
cout << dp[40][n]<<endl;
return 0;
}