整数划分

116 阅读2分钟

因为这道题的变形和其原型,屡次都错了,专门做个笔记来记录一下

一.题目

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

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

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

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

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

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

数据范围 1≤n≤1000

输入样例: 5

输出样例: 7

利用动态规划f[n][n]来表示这一状态,选取前n个数中的一些数组成n,有多少种组成方案。光听这个描述有没有一种很像背包体积的问题?并且这n个物体并没有限制次数,所以是完全背包问题。那这就是一个完全背包问题的变形。

动态规划就要考虑到状态转移方程:对于当前状态前i个数拼凑成j,那么它其实是有前i-1个数来拼凑的,可以不选第i-1个数,也可以选1个,选2个,选无限个

f[i][j] = f[i - 1][j] + f[i - 1][j - i] + f[i - 1][j - 2 * i] + ...

f[i][j - i] = f[i - 1][j - i] + f[i - 1][j - 2 * i] + ... 所以我们可以将f[i][j] = f[i - 1][j] + f[i][j - i]

完整代码:


import java.util.Scanner;

public class IntegerDivsion {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] f = new int[n + 1][n + 1];
        int mod = (int)1e9 + 7;
        for (int i = 0; i <= n;i ++) {
            f[i][0] = 1;
        }
        for (int i = 1;i <= n; i ++) {
            for (int j = 1; j <= n;j ++) {   // 这里的j的范围要是整个,因为是要选取前i个数去凭凑出这个sum的
                f[i][j] = f[i - 1][j] % mod;
                if (j - i >= 0) {
                    f[i][j] = (f[i - 1][j] + f[i][j - i]) % mod;
                }
            }
        }
        System.out.println(f[n][n]);
    }
}