石头划分可以进行优化,在进行集合划分的时候划分k
(枚举分割点)优化
用s[i][j]表示区间[i][j] 的最优分割点,第三重循环可以从[i,j-1] 优化到[s[i][j-1],s[i+1][j]]
通过记录子区间的最优决策来减少当前的决策量 (四边形不等式优化动态规划)
// f[i][j] 代表第i~j的堆的合并集合 属性为最小代价
// 集合划分,最后一步合并入手 假定为k k = 1~ j-1
// f[i][j] = f[i,k] + f[k+1,j] + s[j] - s[i-1];//前缀和
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 310;
int f[N][N];
int n,s[N];
int p[N][N];//p[i][j]表示i~j的最佳分割点
int main()
{
cin >> n;
for(int i = 1; i <= n ; i++) {
cin >> s[i];
s[i] = s[i] + s[i-1];//前缀和
p[i][i] = i;
}
//第一层区间长度,第二层左端点
for(int len = 2; len <= n; len++)
for(int j = 1; j + len -1 <= n; j++){
int l = j, r = j + len -1;
f[l][r] = 0x3f3f3f;
//枚举集合切割点 进行优化
for(int k = p[l][r-1]; k <= p[l+1][r];k++){
if(f[l][k] + f[k+1][r] + s[r]-s[l-1] < f[l][r] ){
f[l][r] = f[l][k] + f[k+1][r] + s[r]-s[l-1];
p[l][r] = k;
}
}
}
// cin >> n;
// for(int i = 1; i <= n; i++) {
// cin >> s[i];
// s[i] = s[i] + s[i-1];
// }
// //枚举所有状态,倒着枚举
// for(int i = n-1; i >=1; i--){
// for(int j = i+1; j <= n; j++){
// int l = i, r = j;
// f[l][r] = 0x3f3f3f3f;
// for(int k = l; k <= r-1; k++){
// f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + (s[r] - s[l-1]));
// }
// }
// }
//枚举所有状态
//枚举区间长度再枚举区间左端点 右端点等于
// for(int len = 2; len <= n; len ++)
// for(int j = 1; j + len -1 <= n; j++){
// int l = j, r = j + len -1;
// f[l][r] = 0x3f3f3f3f;
// for(int k = l; k <= r-1; k++){
// f[l][r] = min(f[l][r],f[l][k] + f[k+1][r] + (s[r]-s[l-1]));
// }
// }
cout << f[1][n];
return 0;
}
// #include <iostream>
// #include <cstring>
// #include <algorithm>
// using namespace std;
// const int N = 310;
// int f[N][N];//表示 区间从i 到 j的合法集合 值为最小值
// int s[N];//存储前缀和
// //石头合并
// int main()
// {
// int n;
// cin >> n;
// for(int i = 1; i <= n; i++) cin >> s[i];
// for(int i = 1; i <= n; i++) s[i] = s[i] + s[i-1];//前缀和
// //枚举所有状态
// //枚举区间长度,再枚举区间左端点
// for(int len = 2; len <= n; len ++)
// for(int j = 1;j+len-1 <= n ;j++){
// int l = j, r = j+len-1;
// f[l][r] = 0x3f3f3f;
// for(int k = l; k <= r-1; k++){
// f[l][r] = min(f[l][r],f[l][k]+f[k+1][r] + s[r]-s[l-1]);
// }
// }
// cout << f[1][n];
// return 0;
// }