有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,因为你这边是利用了余数的运算性质,分次求余,但是因为有减法,就会导致你的结果出现负数,这是不允许的。