石子合并问题java_AcWing 282. 石子合并(java)

该博客主要介绍了如何使用Java解决石子合并问题,强调了与合并果子问题的相似性和区别,指出此题需要考虑区间DP。文章讨论了在实现过程中遇到的问题,如初始化值可能导致的整数溢出,以及二维数组初始化的正确方式。博主提供了错误和正确的代码示例,展示了解决问题的完整过程,并最终给出了正确的解决方案。
摘要由CSDN通过智能技术生成

这题题意看上去和合并果子 那题很相似,合并果子是贪心问题,用小根堆做,把最小的合并就行。

思路

区别在于此题:每次只能合并相邻的两堆,区间DP

最后一步是合并两堆,枚举[L,R]区间上两堆的分界点k,k的取值范围是[L,R-1]

f[L][k]+f[k+1][R]+S[R]-S[L-1]

做此题过程中出现的一些问题,需要注意:

1.f[i][j]因为是求min,故初始化一般为正无穷,但此次不能初始化为Integer.MAX_VALUE,因为f[l][k]+f[k+1][r]+S[r]-S[l-1]会导致int类型溢出,计算机得出的结果就是负数了。故此处初始化为0x3f3f3f3f

2.对二维矩阵进行初始化的操作,最开始采用的是

int[] tmp=new int[N];

Arrays.fill(tmp,INF);

Arrays.fill(f,tmp);

但是这种初始化的方式会出错,值一直不对,不采用,改成直接对f[i][j]赋值。

3.循环枚举求解f[l][r]

此处不能通过枚举左右边界进行循环

因为这样f[k+1][r]会导致当前的f[l][r]计算的晚,故其中为初始化的值0;

//错误的写法

for(int l=1;l<=n;l++){

for(int r=l;r<=n;r++){

for(int k=l;k<=r-1;k++){

f[l][r]=Math.min(f[l][r],f[l][k]+f[k+1][r]+S[r]-S[l-1]);

}

}

}

代码

import java.util.*;

class Main{

static int INF=0x3f3f3f3f;

static int N=310;

static int[] S=new int[N];

static int[][] f=new int[N][N];

public static void main(String[] args){

Scanner sc=new Scanner(System.in);

int n=sc.nextInt();

for(int i=1;i<=n;i++){

S[i]=S[i-1]+sc.nextInt();

f[i][i]=0;

}

//枚举区间长度,保证f[k+1][r]中已经有值

//且符号题意,先去计算原始的俩堆合并的结果,再计算合并后的两堆

//区间长度从2开始,因为堆大小为1的时候,不用合并,代价为0,

for(int len=2;len<=n;len++){

for(int l=1;l+len-1<=n;l++){

int r=l+len-1;

f[l][r]=INF;

for(int k=l;k<=r-1;k++)

f[l][r]=Math.min(f[l][r],f[l][k]+f[k+1][r]+S[r]-S[l-1]);

}

}

System.out.print(f[1][n]);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值