文章目录
核心思路
提示:
本题本质是整数拆分的优化版,是在整数拆分后得到最优解的基础上筛选少的拆分方案。
对于选择最少的拆分方案,可以逆向将得到的最优解dp[i]进行拆分
按照:
dp[i]是当前长度为i的木头拆分得到的最大利润。
dp[i]=j*(i-j)表示长度为i的木头拆成j和i-j的最大利润。
dp[i]=dp[i-j]*j表示长度为i的木头,拆成j并接着拆dp[i-j]得到的最大利润。
三种标准进行逆向拆分,得到最少的拆分数量。
动态规划算法设计流程
动态规划算法设计:
动态规划是求dp【i】的最优解
动态规划特点是当前这一步的dp【i】最优解,是由前一步的最优解dp【i-1】得到的,有递进关系。
动态规划算法设计:
设计起点:如整数拆分,dp【2】=1作为起点
设计状态转移方程:状态转移方程:dp[i]=Math.max(dp[i],Math.max(j*(i-j),dp[i-j]*j))
设计for循环:两层for循环,i从3开始,上限是目标数。j从1开始,上限是i-1。确保从起点开始执行状态转移方程
为了确保拆分后的木材数量最少,可以在得到最优结果dp【i】后,倒序拆分dp【i】判断各个情况下的最少拆分数量,然后存入结果res链表中。
代码细节
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Main{
public static void slice(int x,int[]dp){//动态规划函数
for (int i = 3; i <=x; i++) {//i从3开始,确保最初i-j=2
for (int j = 1; j < i-1; j++) {//j始终停留在i前面一个数
dp[i]=Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
}
}
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int x=scanner.nextInt();
int[] dp=new int[x+1];
dp[2]=1;//初始化dp起点
slice(x,dp);
List<Integer> res=new ArrayList<>();
//拆分dp【i】,寻找各个拆分情况下的最少数量
int m=x;
while (m>=1){
if (dp[m]==m){
res.add(m);//dp【i】直接等于i,不需要拆,可以直接结束while循环
break;
}else {
for (int i = m-1; i >1; i--) {
if (dp[m]==i*(m-i)){
res.add(i);
res.add(m-i);
m=0;//dp【i】可直接拆成两个数,所以不再需要拆分dp【i-j】,让m=0可以结束while循环
break;
} else if (dp[m]==dp[m-i]*i) {
res.add(i);
m-=i;//为下一轮dp【m-i】的拆分做准备
break;
}
}
}
}
for (int i :
res) {
System.out.printf(i+" ");
}
}
}