java---计数dp---整数划分(每日一道算法2022.10.19)

注意事项:
这道题的思考方式和完全背包很像,可以参考我写的完全背包的dp解析:java—dp动态规划—完全背包

题目:
一个正整数 n 可以表示成若干个正整数之和,形如:n = n1+n2+…+nk,其中 n1 ≥ n2 ≥…≥ nk, k ≥ 1
我们将这样的一种表示称为正整数 n 的一种划分
现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法

共一行,包含一个整数 n
共一行,包含一个整数,表示总划分数量
(由于答案可能很大,输出结果请对 109+7 取模)

1 ≤ n ≤ 1000

输入:
5
输出:
7
public class 计数类dp_整数划分 {
    public static int N = 1010, mod = 1000000007, n;

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();

        base();
    }

    //基础版,二维数组三循环
    public static void base() {
        int[][] f = new int[N][N];
        f[0][0] = 1;    //从0中选0,是一种方案

        for (int i = 1; i<=n; i++) {                    //枚举从1-n的所有数i
            for (int j = 0; j<=n; j++) {                //枚举从1-n的所有最终结果j
                for (int k = 0; j >= k*i; k++) {        //枚举对于当前j,选k个i,切记计数dp是+=更新而不是=
                    f[i][j] = (f[i][j] + f[i-1][j - k*i]) % mod;
                }
            }
        }

        System.out.println(f[n][n]);
    }

    //优化版,一维数组双循环
    public static void op() {
        int[] f = new int[N];
        f[0] = 1; //还是0选0为1

        for (int i = 1; i<=n; i++) {
            //直接切掉一维,并且根据状态转移式:f[i][j] = f[i-1][j] + f[i][j-i]
            //可以得知状态是从本层(i)转移而来,所以从小到大枚举状态即可
            for (int j = i; j<=n; j++) {
                f[j] = (f[j] + f[j - i]) % mod;
            }
        }

        System.out.println(f[n]);
    }
}

思路:
经典y式dp法

1.状态表示
f[i][j]:从1-i中选择,总和(想成体积也可以)恰好为 j 的方案数量 (count)

2.状态计算
和完全背包问题类似
1.如果不选第 i 个数,那么就直接将 f[i-1][j] 转移过来即可

2.如果选第 i 个数,并且考虑 i 选1-k个,条件是k * i <= j

总和就应该为 	f[i][j] = f[i-1][j] + f[i-1][j-i] + f[i-1][j-2i] + ... + f[i][j-ki]
而我们发现		f[i][j-i] = 		  f[i-1][j-i] + f[i-1][j-2i] + ... + f[i][j-ki]

所以可以直接等价替换,f[i][j] = f[i−1][j] + f[i][j−i] (看好了这里是 j-i 不是减1啊)

请添加图片描述
借一下Wondery大佬的图

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值