Chinaunix首页 | 论坛 | 博客
  • 博客访问: 62316
  • 博文数量: 30
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 256
  • 用 户 组: 普通用户
  • 注册时间: 2015-09-10 17:54
个人简介

成功,总是从一点一滴小事做起!!!

文章分类

全部博文(30)

文章存档

2016年(5)

2015年(25)

我的朋友

分类: C/C++

2015-11-14 23:42:55

题目: 有n种物品, 第i种物品有a个. 不同种类的物品可以互相区分, 但相同种类的无法区分.
从这些物品中取出m个, 有多少种取法? 求出数模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).
使用动态规划(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]
时间复杂度O(nm).
主要是在进行递推之钱还要记得,要先给dp赋一个初值1,要赋初值的也只是每一行的第一个数,也就是dp[i][0]=1;
还有在递推时候,还要注意的一个问题就是dp[i][j-1-a]这里的时候,要进行判断一下,如果j-1-a的值小于0那个就把这个dp去掉,因为我们的数组
在这里不支持负数。这里是一些个人的代码:
仅供参考:

#include
#include
#include
using namespace std;
const int maxn=1010;
int n,m,mod;
int a[maxn];
int dp[maxn][maxn];
int main()
{
    while(~scanf("%d%d%d",&n,&m,&mod))
    {
        for(int i=0; i             scanf("%d",&a[i]);
        for(int i=0; i<=n; i++) 
            dp[i][0]=1;
        for(int i=0; i             for(int j=1; j<=m; j++)
            {
                if(j-1-a[i]>=0)
                    dp[i+1][j]=(dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]]+mod)%mod;//记得这里要在里面加上mod,不然会造成错误,因为当dp[i][j-1-a[i]]
                                                                                                                            //很大时会变成负数的情况发生
                else
                    dp[i+1][j]=(dp[i+1][j-1]+dp[i][j])%mod;
            }
        printf("%d\n",dp[n][m]);
    }
}



阅读(1087) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~