AcWing-900.整数划分(java实现)

AcWing-900.整数划分

题目描述

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

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

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

输入格式

共一行,包含一个整数 n。

输出格式

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

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

数据范围

1≤n≤1000

输入样例:

5

输出样例:

7

思路(朴素版)

状 态 表 示 : f ( i , j ) , 表 示 从 1   i 中 选 刚 好 可 以 拼 成 j 的 所 有 方 法 状态表示:f(i,j),表示从1~i中选刚好可以拼成j的所有方法 f(i,j),1 ij

属 性 : 数 量 属性:数量

核 心 : 最 后 一 个 数 i 不 取 或 者 取 k 个 正 好 拼 成 j 核心:最后一个数i不取或者取k个正好拼成j :ikj

状 态 划 分 : f ( i − 1 , j ) 取 0 个 i , 1 个 i … … , k 个 i 变 为 f ( i , j ) 状态划分:f(i-1,j)取0个i,1个i……,k个i变为f(i,j) :f(i1,j)0i,1i,kif(i,j)

由状态划分可得到状态转移方程:
f ( i , j ) = f ( i − 1 , j ) + f ( i − 1 , j − i ) + f ( i − 1 , j − 2 i ) + … … + f ( i − 1 , j − k i ) f(i,j) = f(i-1,j)+f(i-1,j-i)+f(i-1,j-2i)+……+f(i-1,j-ki) f(i,j)=f(i1,j)+f(i1,ji)+f(i1,j2i)++f(i1,jki)

f ( i , j − i ) =                 f ( i − 1 , j − i ) + f ( i − 1 , j − 2 i ) + … … + f ( i − 1 , j − k i ) f(i,j-i) = ~~~~~~~~~~~~~~~f(i-1,j-i)+f(i-1,j-2i)+……+f(i-1,j-ki) f(i,ji)=               f(i1,ji)+f(i1,j2i)++f(i1,jki)

相减得最终的状态转移方程:
f ( i , j ) = f ( i − 1 , j ) + f ( i , j − i ) f(i,j) = f(i-1,j)+f(i,j-i) f(i,j)=f(i1,j)+f(i,ji)

核心代码

		for(int i=1;i<=n;i++) {
			for(int j=0;j<=n;j++) {
	            dp[i][j] = dp[i - 1][j] % MOD; //	如果容量j小于i的话,不能对i进行选择。
	            if (j >= i) {	//只有容量j大于等于i时,才能对i的选择多少进行讨论
					dp[i][j] = (dp[i-1][j]+dp[i][j-i]) % MOD;
	            }
			}
		}

完整代码

package acWing900;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Main {
	static int N = 1010,MOD = (int) (1e9+7);
	static int n;
	static int dp[][] = new int[N][N];
	public static void main(String[] args) throws Exception{
		Read r = new Read();
		n = r.nextInt();
		for(int i=1;i<=n;i++) {
			dp[0][i] = 0;	//	当容量为i有0个物品一个则没有方案。
		}
		for(int i=0;i<=n;i++) {
			dp[i][0] = 1;	//	当容量为0前i个物品一个不选也是一种方案。
		}
		// 特殊 dp[0][0] = 1
		for(int i=1;i<=n;i++) {
			for(int j=0;j<=n;j++) {
	            dp[i][j] = dp[i - 1][j] % MOD; //	如果容量j小于i的话,不能对i进行选择。
	            if (j >= i) {	//只有容量j大于等于i时,才能对i的选择多少进行讨论
					dp[i][j] = (dp[i-1][j]+dp[i][j-i]) % MOD;
	            }

			}
		}
		System.out.println(dp[n][n]);
	}
class Read{
	StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	public int nextInt() throws Exception{
		st.nextToken();
		return (int)st.nval;
	}
}

降维(利用滚动数组)

合并得最终的状态转移方程为:
f ( i , j ) = f ( i − 1 , j ) + f ( i , j − i ) f(i,j) = f(i-1,j)+f(i,j-i) f(i,j)=f(i1,j)+f(i,ji)
由状态方程可知,需要利用的仅有当前行和上一行所以可以利用滚动数组的概念将二维降至一维,即:
f ( j ) = f ( j ) + f ( j − i ) f(j) = f(j) + f(j-i) f(j)=f(j)+f(ji)

核心代码:

		for(int i=1;i<=n;i++) {
			for(int j=i;j<=n;j++) {
				dp[j] = (dp[j]+dp[j-i]) % MOD;
			}
		}

完整代码:

package acWing900;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Main {
	static int N = 1010,MOD = (int) (1e9+7);
	static int n;
	static int dp[] = new int[N];
	public static void main(String[] args) throws Exception{
		Read r = new Read();
		n = r.nextInt();
		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;
			}
		}
		System.out.println(dp[n]);
	}
}
class Read{
	StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	public int nextInt() throws Exception{
		st.nextToken();
		return (int)st.nval;
	}
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜柠函

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值