整数拆分问题解析

今天给大家带来一篇整数拆分问题的讲解,希望大家能喜欢。


整数拆分问题是一类非常经典的动态规划问题,在2020NOI ONLINE中PJ T2出现,当时可谓难倒一片dalao,今天就以这道题来解读整数拆分问题。

题面:

题目描述

小 H 是一个热爱运动的孩子,某天他想给自己制定一个跑步计划。小 H 计划跑 n n 米,其中第 i ( i 1 ) i(i≥1) 分钟要跑 x i x_i ​ 米( x i x_i 是正整数),但没有确定好总时长。
由于随着跑步时间增加,小 H 会越来越累,所以小 H 的计划必须满足对于任意 i ( i > 1 ) i(i>1) 都满足 x i x i 1 x_i≤x_i−1
现在小 H 想知道一共有多少个不同的满足条件的计划,请你帮助他。两个计划不同当且仅当跑步的总时长不同,或者存在一个 iii,使得两个计划中 x i x_i 不相同。
由于最后的答案可能很大,你只需要求出答案对 p p 取模的结果。

输入格式

输入只有一行两个整数,代表总米数 n n 和模数 p p

输出格式

输出一行一个整数,代表答案对 p p 取模的结果。

输入样例
4 44
输出样例
5

题面解读:

这道题就是整数拆分问题的一个很典型的应用(话说这就是裸的整数拆分 ),附上真正整数拆分问题的题面:

将一个正整数 n n 拆分成一系列正整数之和,即: n = n 1 + n 2 + n 3 + + n k n = n_1 + n_2 + n_3 + …… + n_k ,其中 n 1 n 2 n 3 n k 1 n_1 \ge n_2 \ge n_3 \ge …… \ge n_k \ge 1 k 1 k \geq 1 。这种表示方法叫做 n n 的拆分,求 m m 的不同拆分的个数。

题目分析

这道题可以用完全背包的方法去做,分析一下,可以把 m m 的大小当成体积,把拆分的数量当成完全背包的方案数,把每一个 n i n_i 当成物品的体积。
因为完全背包的状态转移方程为: d p [ i ] [ j ] = m a x ( d p [ i 1 ] [ j ] , d p [ i ] [ j c [ i ] ] + w [ i ] ) dp[i][j] = max(dp[i - 1][j] , dp[i][j - c[i]] + w[i])
所以求完全背包的方案数的状态转移方程为: d p [ i ] [ j ] = d p [ i 1 ] [ j ] + d p [ i ] [ j c [ i ] ] dp[i][j] = dp[i - 1][j] + dp[i][j - c[i]]
将其类推到整数拆分问题上,可得: d p [ i ] [ j ] = d p [ i 1 ] [ j ] + d p [ i ] [ j i ] dp[i][j] = dp[i - 1][j] + dp[i][j - i]

上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e3 + 9;
const int mod = 1e9 + 9;  //取模
int f[N];
int main() {
    //freopen("divide.in", "r", stdin);
    //freopen("divide.out", "w", stdout);
    memset(f, 0, sizeof f);
    f[0][0] = 1;
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j <= n; ++j) {
            if(j >= i) {
    		f[i][j] = f[i][j - i] + f[i - 1][j];  //状态转移
   	    } 
            else {
                f[i][j] = f[i - 1][j];   //边界条件
            }
        }
    }
    cout << f[n][n] << endl;
    return 0;
}

整数拆分问题空间复杂度优化

我们知道完全背包能优化空间复杂度,那么整数拆分问题可以吗?

答案是肯定的。同理,完全背包求方案数的优化后转移方程是: d p [ j ] = d p [ j c [ i ] ] + d p [ j ] dp[j] = dp[j - c[i]] + dp[j]
以此类推,整数拆分问题的转移方程是: d p [ j ] = d p [ j ] + d p [ j i ] dp[j] = dp[j] + dp[j - i]

上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e3 + 9;
const int mod = 1e9 + 9;
int f[N];
int main() {
    //freopen("divide.in", "r", stdin);
    //freopen("divide.out", "w", stdout);
    int t;
    cin >> t;
    f[0] = 1;
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        for (int j = i; j <= n; ++j) {
           (f[j] += f[j - i]) %= mod;
        }
    }
    cout << f[n] << endl;
    return 0;
}

END

发布了11 篇原创文章 · 获赞 1 · 访问量 547

猜你喜欢

转载自blog.csdn.net/live_now/article/details/105059521