问题描述:
给定一个正数1,裂开的方法有一种,
(1) 给定一个正数2,裂开的方法有两种,(1和1)
(2) 给定一个正数3,裂开的方法有三种,(1、1、1)、(1、2)
(3) 给定一个正数4,裂开的方法有五种,(1、1、1、1)、(1、1、2)、(1、3)、(2、2)
(4)给定一个正数n,求裂开的方法数。 动态规划优化状态依赖的技巧,注意裂开时后一种方法不能小于前一种。
代码:
代码一:暴力求解
/**
*
* @param pre 要裂开的rest的前一个约束(rest裂开的第一个部分不能<pre)
* @param rest 还剩下多少需要裂开
* @return 裂开的方法数
*/
public static int process(int pre,int rest){
if (rest ==0){
//之前裂开的方案,构成了1中有效方法
return 1;
}
//如果rest还剩下东西
if (pre >rest){
return 0;
}
int ways = 0;
for (int i =pre;i<=rest;i++){
ways += process(i,rest-i);
}
return ways;
}
代码二:暴力求解转化为动态规划
public static int ways2(int n){
if (n<1){
return 0;
}
int[][] dp = new int[n+1][n+1];
for (int pre = 1;pre<=n;pre++){
dp[pre][0] = 1;
}
for (int pre = n;pre>=1;pre--){
for (int rest = pre;rest<=n;rest++){
int ways = 0;
for (int i =pre;i<=rest;i++){
ways += dp[i][rest-i];
}
dp[pre][rest] = ways;
}
}
return dp[1][n];
}
代码三:对动态规划进行优化,消除枚举过程
public static int ways3(int n){
if (n<1){
return 0;
}
int[][] dp = new int[n+1][n+1];
for (int pre = 1;pre<dp.length;pre++){
dp[pre][0] = 1;
}
for (int pre = 1;pre<dp.length;pre++){
dp[pre][pre] = 1;
}
for (int pre = n-1;pre>0;pre--){
for (int rest = pre+1;rest<=n;rest++){
dp[pre][rest] = dp[pre+1][rest]+dp[pre][rest-pre];
}
}
return dp[1][n];
}
public static void main(String[] args) {
int n = 20;
System.out.println(way1(n));
System.out.println(ways2(n));
System.out.println(ways3(n));
}