DP - 完全背包 - 整数划分

DP - 完全背包 - 整数划分

本 题 与 — — 本题与—— 《Pay the Price - UVA - 10313》 类 似 。 类似。

一个正整数n可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中n1≥n2≥…≥nk,k≥1。

我们将这样的一种表示称为正整数n的一种划分。

现在给定一个正整数n,请你求出n共有多少种不同的划分方法。

输入格式
共一行,包含一个整数n。

输出格式
共一行,包含一个整数,表示总划分数量。

由于答案可能很大,输出结果请对109+7取模。

数据范围
1≤n≤1000

输入样例:
5
输出样例:
7

分析:

将 n 分 解 为 n 个 小 于 等 于 n 的 正 整 数 的 和 , 等 价 于 从 小 于 等 于 n 的 n 个 正 整 数 中 选 择 一 些 数 拼 凑 成 n 。 将n分解为n个小于等于n的正整数的和,等价于从小于等于n的n个正整数中选择一些数拼凑成n。 nnnnnn

将 小 于 等 于 n 正 整 数 n i 视 作 体 积 为 n i 的 物 品 , n 视 作 背 包 容 量 , 问 题 转 化 为 完 全 背 包 求 方 案 总 数 。 将小于等于n正整数n_i视作体积为n_i的物品,n视作背包容量,问题转化为完全背包求方案总数。 nninin

状 态 表 示 : f [ i ] [ j ] : 考 虑 小 于 等 于 i 的 数 , 求 和 恰 好 为 j 的 方 案 总 数 。 状态表示:f[i][j]:考虑小于等于i的数,求和恰好为j的方案总数。 f[i][j]:ij

状 态 计 算 : ① 、 不 包 含 整 数 i : f [ i ] [ j ] = f [ i − 1 ] [ j ] 。 ② 、 包 含 k 个 整 数 i : f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − k × i ] , k > = 1 且 j − k × i > = 0 。 状态计算:\\①、不包含整数i:f[i][j]=f[i-1][j]。\\②、包含k个整数i:f[i][j]=f[i-1][j]+f[i-1][j-k×i],k>=1且j-k×i>=0。 i:f[i][j]=f[i1][j]kif[i][j]=f[i1][j]+f[i1][jk×i]k>=1jk×i>=0

完 全 背 包 优 化 , 包 含 整 数 i 时 : f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − i ] + f [ i − 1 ] [ j − 2 × i ] + . . . + f [ i − 1 ] [ j − k × i ] 完全背包优化,包含整数i时:\\f[i][j]=f[i-1][j]+f[i-1][j-i]+f[i-1][j-2×i]+...+f[i-1][j-k×i] if[i][j]=f[i1][j]+f[i1][ji]+f[i1][j2×i]+...+f[i1][jk×i]

f [ i ] [ j − i ] = f [ i − 1 ] [ j − i ] + f [ i − 1 ] [ j − 2 × i ] + . . . + f [ i − 1 ] [ j − k × i ] f[i][j-i]=\qquad \qquad f[i-1][j-i]+f[i-1][j-2×i]+...+f[i-1][j-k×i] f[i][ji]=f[i1][ji]+f[i1][j2×i]+...+f[i1][jk×i]

于 是 有 f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i ] [ j − i ] 。 于是有f[i][j]=f[i-1][j]+f[i][j-i]。 f[i][j]=f[i1][j]+f[i][ji]

由 于 包 含 整 数 i 是 从 第 i 层 转 移 过 来 的 , 因 此 优 化 到 一 维 是 从 小 到 大 枚 举 j 。 由于包含整数i是从第i层转移过来的,因此优化到一维是从小到大枚举j。 iij

二维代码:

#include<iostream>
#include<algorithm>

using namespace std ;

const int N=1010,mod=1e9+7;

int n,f[N][N];

int main()
{
    cin>>n;
    
    f[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=n;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=i) f[i][j]=(f[i-1][j]+f[i][j-i])%mod;
        }
                
    cout<<f[n][n]<<endl;
    
    return 0;
}

一维代码:

#include<iostream>
#include<algorithm>

using namespace std ;

const int N=1010,mod=1e9+7;

int n,f[N];

int main()
{
    cin>>n;
    
    f[0]=1;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
            f[j]=(f[j]+f[j-i])%mod;
            
    cout<<f[n]<<endl;
    
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值