整数划分

整数划分

问题描述: 将正整数 n n n 表示为若干个正整数的和, 问共有多少种表示? (不考虑排列问题)

上述描述是整数划分中最基本的描述, 整数划分是一类问题的总称. 正整数及其个数的不同约束可以得到不同的整数划分问题.

1. 最大值为 k k k 的正整数

该问题是最基本的约束条件, 对该约束分析如下:

f ( n , k ) f(n,k) f(n,k) 为问题的解 ( 即将正整数 n n n 划分为不大于 k ( k ≥ 1 ) k (k \geq 1) k(k1) 的正整数和的划分个数 ) , 则有下述等式成立

f ( n , k ) = { 0 , n < 0 且 k ≤ 0 ; 1 , n = 0 ; f ( n , n ) , k > n ; f ( n , k − 1 ) + f ( n − k , k ) , k ≤ n . f(n,k) = \begin{cases} 0, & \text{$n<0且k\le 0;$} \\[2ex] 1, & \text{$n=0;$} \\[2ex] f(n,n), & \text{$k>n;$} \\[2ex] f(n,k-1)+f(n-k,k), & \text{$k\leq n.$} \end{cases} f(n,k)=0,1,f(n,n),f(n,k1)+f(nk,k),n<0k0;n=0;k>n;kn.

根据上述结果, 得到如下 C++ 程序

int dp(int n, int k) 
{
	/*
		求 n 的最大值为 k 的划分的个数
		f(n, k) = f(n, k - 1) + f(n - k, k)
		由上式可得: dp[n] += dp[n - k], (n >= k 且 dp[0] = 1)
	*/
	if (n <= 0 || k <= 0)
		return 0;

	int dp[128] = { 1 };
	int realK = k <= n ? k : n;
	int iN, jK;

	for (jK = 1; jK <= realK; ++jK)
		for (iN = jK; iN <= n; ++iN)
			dp[iN] += dp[iN - jK];

	return dp[n];
}

2. 若干个奇正整数

该问题可以转化为问题 5 进行解决.

3. 若干个不同的正整数

该问题是最基本的约束条件, 对该约束分析如下:

f ( n , k ) f(n,k) f(n,k) 为问题的解 ( 即将正整数 n n n 划分为不大于 k ( k ≥ 1 ) k (k \geq 1) k(k1) 的正整数和的划分个数 ) , 则有下述等式成立

f ( n , k ) = { 0 , n ≤ 0 或 k ≤ 0 ; 1 , n = 1 且 k > 0 ; f ( n , n ) , n > 1 且 k > n ; f ( n , k − 1 ) + f ( n − k , k − 1 ) , n > 1 且 k ≤ n . f(n,k) = \begin{cases} 0, & \text{$n\leq 0 或 k\leq 0;$} \\[2ex] 1, & \text{$n=1且k>0;$} \\[2ex] f(n,n), & \text{$n> 1 且 k>n;$} \\[2ex] f(n,k-1)+f(n-k,k - 1), & \text{$n>1 且 k\leq n.$} \end{cases} f(n,k)=0,1,f(n,n),f(n,k1)+f(nk,k1),n0k0;n=1k>0;n>1k>n;n>1kn.

根据上述结果, 得到如下 C++ 程序

int dpOfDifNum(int n, int k) 
{
	/*
		求 n 的最大值为 k 的划分的个数
		f(n, k) = f(n, k - 1) + f(n - k, k - 1)
		由上式可得: dp[n] += dp[n - k], (n >= k 且 dp[0] = 1)
	*/
	if (n <= 0 || k <= 0)
		return 0;

	int dp[128] = { 1 };
	int realK = k <= n ? k : n;
	int iN, jK;

	for (jK = 1; jK <= realK; ++jK)
		for (iN = n; iN >= jK; --iN)
			dp[iN] += dp[iN - jK];

	return dp[n];
}

4. 若干个给定的正整数

该问题根据最基本的问题推导:

设给定的 m m m 个正整数为 k 1 , k 2 , . . . , k m k_1,k_2,...,k_m k1,k2,...,km ,记个数为 f ( n ) f(n) f(n) , 则有一下等式成立

f ( n , k i ) = { 0 , n < 0 ; 1 , n = 0 ; f ( n , n ) , n > 0 且 k i > n ; f ( n , k i − 1 ) + f ( n − k i , k i ) , n > 0 且 k i ≤ n . f(n,k_i) = \begin{cases} 0, & \text{$n<0;$} \\[2ex] 1, & \text{$n=0;$} \\[2ex] f(n,n), & \text{$n>0 且 k_i>n;$} \\[2ex] f(n,k_{i-1})+f(n-k_i,k_i), & \text{$n>0 且 k_i\leq n.$} \end{cases} f(n,ki)=0,1,f(n,n),f(n,ki1)+f(nki,ki),n<0;n=0;n>0ki>n;n>0kin.

根据上述结果, 得到如下 C++ 程序

int dpMArr(vector<int>& mArr, int n)
{
	/* 
		mArr 给定的正整数
		n 需要求的数
	*/
	if (mArr.size() <= 0 || n <= 0)
		return 0;

	int dp[10240] = { 1 };
	int m = mArr.size(),
		realM = m <= n ? m : n;
	int iN, jM;

	for (jM = 0; jM < realM; ++jM)
		for (iN = mArr[jM]; iN <= n; ++iN)
			dp[iN] += dp[iN - mArr[jM]];

	return dp[n];
}

5. m 个正整数之和

该问题是最基本的约束条件, 对该约束分析如下:

给问题等价于 ( n − m ) (n-m) (nm) 的最大值为 m m m 的划分的个数。

f ( n , k ) f(n,k) f(n,k) 为问题 1 的解 ( 即将正整数 n n n 划分为不大于 k ( k ≥ 1 ) k (k \geq 1) k(k1) 的正整数和的划分个数 ) , 则该问题的解为 f ( n − m , m ) f(n-m,m) f(nm,m)

根据上述分析, 得到如下 C++ 程序

int mSumOfNum(int n, int m)
{
	return dp(n - m, m);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值