动态规划(多重集组合数)

有n种物品,第i种物品有ai个。不同种类的物品可以互相区分但相同种类的无法区分。从
这些物品中取出m个的话,有多少种取法。
int main()
{
while(cin >> n >> m){
for(int i = 0;i < n;i++){
cin >> a[i];
}
int M;

    cin >> M;
    for(int i = 0;i <= n;i++){
        dp[i][0] = 1;
    }
    for(int i = 0;i < n;i++){
        for(int j = 1;j <= m;j++){
            if(j -1 - a[i] >= 0)
                dp[i+1][j] = (dp[i][j] + dp[i+1][j-1] - dp[i][j-1-a[i]] +M)%M; //
                这句话什么意思~~求大神指教(他为什么能到了a[i]+1个,不是就a[i]个吗)
            else{
                dp[i+1][j] = dp[i][j] + dp[i+1][j-1];//还有这句 
            }
        }
    } 
printf("%d\n",dp[n][m]);
}   
return 0;

}

下标是否越界的问题,计算一下循环的边界值就可以确定。

例如: 有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).
使用动态规划(DP).
前i+1种物品取出j个 = 前i+1种物品取出j-1个 + 前i种物品取出j个 - 前i种物品中取出j-1-a个.
因为取出j-1-a个, 最后需要j-1个, 则a需要全部取出, 前两个相重复, 则必然全部取出.
递推公式: dp[i+1][j] = dp[i+1][j-1] + dp[i][j] - dp[i][j-1-a]

这个程序因为只要统计个数,不需要那么麻烦,递归下就可以了

 #include <iostream>
using namespace std;

int foo(int n, int idx, int m)
{
    if (m == 0) return 1;
    int sum = 0;
    for (int i = 0; i <= idx && i <= m && idx <= n; i++)
    {
        sum += foo(n, idx + 1, m - i);
    }
    return sum;
}

int main()
{
    cout << foo(4, 1, 2) << endl;
}

简单说下思路,就是从前往后,每一个物品取有0~i个取法,只要没有取够N,就再取下一种物品。
最后把这些可能性叠加下就成了。

调用方式:
foo(N, 1, M)

楼主这边理解错了,(a+m)%m是等于a%m的,求余数和除法弄混了哈,至于为什么要加上一个m,因为你这边是利用了余数的运算性质,分次求余,但是因为有减法,就会导致你的结果出现负数,这是不允许的。