设石子总数为n
所求问题:1到n这些石子合并最少需要多少代价
由于石子合并的顺序可以任意,我们将石子分为两个部分
子问题:1到k这堆石子合并,k+1到n这堆石子合并,再把两堆石子合并,需要多少代价(1<=k<=n)
那么便可以得到状态转移方程 dp[i][j]=min(dp[i][k]+dp[k+1][j]+……)
i到j这些石子合并,代价不仅仅是分开的两堆内部合并的代价,还有两堆石子相互合并的所带来的代价消耗,可得出省略号中的答案为a[i]+a[i+1]+……+a[j]
为了加快效率,我们设立一个sum数组来记录前缀和,那么可得到完整的状态转移方程:
dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
需要注意的是,由于dp求最小值,需要将dp预处理为无穷大,以下便是本题的AC代码:
#include <bits/stdc++.h> using namespace std; int a[1050]; int sum[1050]; int dp[1050][1050]; int main() { memset(dp,0x3f,sizeof(dp)); int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=a[i]+sum[i-1]; } for(int j=1;j<=n;j++) { for(int i=j;i>=1;i--) { if(i==j) dp[i][j]=0; for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); } } printf("%d\n",dp[1][n]); }