加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 3014 整数划分

(2010-05-15 20:57:21)
标签:

poj

pku

3014

it

分类: 动态规划

题目描述:

给你m个东西,放在n个相同的盒子中(相同,即不计顺序),每个盒子可以放任意多,问有多少种放法。

解题报告:

整数划分问题。

dp[i][j]表示j个东西放i个盒子中的方法数。

则i个盒子的状态只有2种:有空的,和没有空的。

即dp[i][j] = 有空的 + 没有空的。

情况1:j < i

没有空的方法数为0,有空的时,把一个盒子单独拿出来当做空的,剩下的任意放

就是dp[i - 1][j]

综上,dp[i][j] = dp[i - 1][j] + 0

情况2:j == i

没有空的时,有且仅有一种情况。

有空的时,方法同上,单独取出一个,方法数:dp[i - 1][j]

综上 dp[i][j] = dp[i - 1][j] + 1

情况3:j > i

没有空的时,可以从j中拿出i个依次放到i个盒子中,剩下的随便放即可,方法数dp[i][j - i]

有空的时,同上,dp[i - 1][j]

综上 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

另外,由于2 * 1000000007也可以放在int下,所以可以不用模运算,当超过1000000007时,减去它就可以了,可以节省不少时间。

代码如下:

#include<iostream>
using namespace std;
#define size 4501
int n, m, dp[size][size];
int main()
{
    scanf("%d%d", &n ,&m);
    for(int i = 1; i <= m; i++) dp[1][i] = 1;
    for(int i = 2; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            dp[i][j] = dp[i - 1][j];
            if (i == j) dp[i][j]++;
            if (j > i) dp[i][j] += dp[i][j - i];
            if (dp[i][j] >= 1000000007) dp[i][j] -= 1000000007;
        }
    }
    printf("%d\n", dp[n][m]);
    return 0;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有