整数划分 51Nod - 1201 (经典dp)

整数划分 51 Nod - 1201

将N分为若干个不同整数的和,有多少种不同的划分方式,例如:n = 6,{6} {1,5} {2,4} {1,2,3},共4种。由于数据较大,输出Mod 10^9 + 7的结果即可。

Input
输入1个数N(1 <= N <= 50000)。

Output
输出划分的数量Mod 10^9 + 7。

Sample Input
6

Sample Output
4

这道题 刚写的时候 使用的 dfs 但是 由于 数据很大 ,所以 会超时 ,想着 优化一下,但是 dfs 与 bfs 本身 就是 比较 费时的 所以 就没写出来,其实 我自己 也想到啦 这道题 很可能是 用 dp 写的, 但是 动态规划方程 想不到 是什么, 去网上 搜了 题解 才明白了, 感觉 真是 好题 所以 写出来跟大家分享一下!

这道题的 动态转移方程为:
dp[ i ][ j ] = dp[ i-j ][ j ] + dp[ i-j ][ j-1 ]

dp[ i ][ j ] 表示 用 j 个数 子 组成 i 的 不同的 组合种类, dp[ i-j ][ j ] 表示 组成 i-j 的 j 个数字 全部都 加上 一个 一 之后 刚好 等于 i 刚好也是 用 j 个数 组成 i 的 不同 组合种类 中的 其中 一部分 种类, dp[ i-j ][ j-1 ] 表示的意思是: 用 j-1 个数 来组成 i-j+1 但是 呢 应为 原来 组成 i-j 的 j 个数 都已经 加上了 一 所以 都比一大 , 上式之所以仍然写作 i-j 是应为 这里 除了 j-1 个数字 之外 包含了 一个 一 。我也是 想了之后 才明白的 !

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int mod = 1e9 + 7;

int main()
{
    int n;

    while(~scanf("%d", &n))
    {
        int ans;
        static int dp[50100][350];

        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;

        for(int j = 1; j < 350; j++)
        {
            for(int i = 0; i <= n; i++)
                if(i - j >= 0)
                    dp[i][j] = (dp[i-j][j] + dp[i-j][j-1]) % mod;
        }

        ans = 0;
        for(int j = 1; j < 350; j++)
            ans = (ans + dp[n][j]) % mod;

        printf("%d\n", ans);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值