自然数的拆分(完全背包)

给定一个自然数N,要求把N拆分成若干个正整数相加的形式,参与加法运算的数可以重复。与“自然数拆分问题”类似,同样需要满足方案的不重复。

所谓拆分方式的重复性判定如下:给定N=a
​1
​​ +a
​2
​​ +…a
​m1
​​ 和 N=b
​1
​​ +b
​2
​​ +…b
​m2
​​ 表示整数N的两种拆分方式。对于∀a
​i
​​ ,b
​j
​​ ≥1,令集合A={a
​i
​​ ∣1≤i≤m
​1
​​ },B={b
​j
​​ ∣1≤j≤m
​2
​​ }。若满足集合A=B,则称这两种拆分方式是重复的。

例如 6 = 3 + 2 和 6 = 2 + 3, 就是重复的拆分方式。

现在需要你求满足条件的拆分有多少种?
输入格式:
第一行自然整数T,表示之后测试数据组数, 以后T行,每行一个自然数N,(1<N<=4000)

注意:本题规模为4000,回溯法还合适吗?仔细思考应该如何设计算法

建议自行学习完全背包相关知识

输出格式:
T行,每行输出一个整数,表示拆分的方案数,结果对2147483648取模。

输入样例:
在这里给出一组输入。例如:

2
6
7

输出样例:
在这里给出相应的输出。例如:

11
15

分析:
虽然可以用回溯法去解决,但是当规模大的时候,回溯法需要的时间太长。就使用完全背包知识。
思路:

将一个数差分成若干个数,很显然其中某些数可能会出现多次, 就是说这些数可以用无限多次来构成最初的数,这就是完全背包问题:有n个物品,每个物品可以选无限多次,求选出的若干个物品的价值之和恰好为n的方案个数。

在完全背包中 状态转移方程
dp[i][k] = dp[i][k - 1] + dp[i - num[k]][k];
很明显,两者如出一辙,只是变成了一维。

#include<bits/stdc++.h>
using namespace std;
const int Max = 4001;
const int mod = 2147483648;

int n;
void oper(){
	long long dp[Max]={0};
	cin >> n;
    dp[0] = 1;
    for(int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j++) {
            dp[j] = (dp[j] + dp[j - i]) % mod;
        }
    }
    cout << dp[n]<<endl;
}
int main () {
	int t;
    cin>>t;
    while(t>0){
    	oper();
    	t--;
    }
    return 0;
}

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值