多重集组合数 (来源:《挑战程序设计竞赛》)
有n种物品, 第i种物品有ai个. 不同种类的物品可以互相区分, 但相同种类的无法区分.
从这些物品中取出m个, 有多少种取法?
例如: 有n=3种物品, 每种a={1,2,3}个, 取出m=3个, 取法result=6(0+0+3, 0+1+2, 0+2+1, 1+0+2, 1+1+1, 1+2+0).
输入:
3 3
1 2 3
输出:
6
分析见注释:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int dp[N][N]; //dp[i][j]:前i种物品选j个的选法数量
int a[N];
int n, m;
int main()
{
cin >> n >> m ;
for (int i = 1;i <= n;i++) cin >> a[i];
for (int i = 0;i <= n;i++) dp[i][0] = 1; //i种物品选0个都是只有一种选法
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= m;j++)
{
/*for (int k = 0;k <= a[i];k++) //第i种物品选k个
{
dp[i][j] += dp[i-1][j - k];
}
推导:dp[i][j]=d[i-1][j]+dp[i-1][j-1]+dp[i-1][j-2]+...+dp[i][j-(a-1)]+dp[i][j-a] ①
dp[i][j-1]= dp[i-1][j-1]+dp[i-1][j-2]+...+dp[i][j-(a-1)]+dp[i][j-a]+dp[i][j-a-1] ②
①式-②式,得 dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1 - a[i]]
*/
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1 - a[i]]; //等效公式
}
}
cout << dp[n][m] << endl;
return 0;
}