合并类动态规划
- 合并:意思就是将两个或多个部分进行整合,当然也可以反过来,也就是是将一个问题进行分解成两个或多个部分。
- 特征:能将问题分解成为两两合并的形式
- 求解:对整个问题设最优值,枚举合并点,将问题分解成为左右两个部分,最后将左右两个部分的最优值进行合并得到原问题的最优值。有点类似分治算法的解题思想。
- 典型试题:整数划分,凸多边形划分、石子合并、多边形合并、能量项链等。
- 主要思路:将整区间分成所有可以分成的小区间,依次遍历求最小最大值。
普遍模板:
for(int len=1; len<=n; len++){ //依次遍历区间长度
for(int i=1; i+len-1<=n; i++){
int j = i + len - 1; //i为区间起点,j为终点
for(int k=i; k<j; k++){
f[i][j] = min/max(f[i][j], f[i][k]+f[k+1][j]+a[k]);
}
}
}
例题
样例输入:
4
4 5 9 4
样例输出:
44
54
解:
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n;
int f[N][N], g[N][N];
int a[N], s[N];
int main(){
scanf("%d",&n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
s[i] = s[i-1] + a[i]; //前缀和预处理
}
memset(f, 0x3f, sizeof(f));
for(int i=1; i<=n; i++) f[i][i] = 0;
for(int len=1; len<=n; len++){
for(int i=1; i+len-1<=n; i++){
int j = i + len - 1;
for(int k=i; k<j; k++){
f[i][j] = min(f[i][j], f[i][k]+f[k+1][j]+s[j]-s[i-1]);
g[i][j] = max(g[i][j], g[i][k]+g[k+1][j]+s[j]-s[i-1]);
}
}
}
printf("%d\n", f[1][n]);
printf("%d\n", g[1][n]);
return 0;
}
标签:int,样例,合并,区间,最优,左右两个,dp
From: https://www.cnblogs.com/zyzAqr/p/18018214