区间dp
第一维,枚举区间长度len。
当区间长度为1时,说明是该堆石子本身,代价为0;
所以,区间长度可以直接从2开始。
第二维,枚举区间左端点。(右端点:可以根据区间长度和左断点计算出)
第三维,区间[i,j]中一个不等于j的点(若k=j,则k+1越界)
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] + s u m [ j ] − s u m [ i − 1 ] ) f[i][j] = min(f[i][j] , f[i][k] + f[k+1][j] + sum[j] - sum[i - 1]) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]−sum[i−1])
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 310 + 10;
using namespace std;
// const int N
int f[N][N];
int n;
int sum[N];
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%d",&sum[i]),sum[i] += sum[i-1];
for(int len = 2; len <= n; len ++){
for(int i = 1; i + len - 1 <= n; i++){
int j = i + len - 1;
f[i][j] = 1e9;
for(int k = i; k < j; k++){//若k=j,则k+1越界
f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + sum[j] - sum[i - 1]);
}
}
}
printf("%d\n",f[1][n]);//从第一堆石子开始合并到第n堆石子。
return 0;
}
记忆化搜索
和dp思路好像,核心部分 d p ( i , k ) + d p ( k + 1 , j ) + s u m [ j ] − s u m [ i − 1 ] dp(i,k) + dp(k + 1, j) + sum[j] - sum[i - 1] dp(i,k)+dp(k+1,j)+sum[j]−sum[i−1]一样。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 310;
int f[N][N];
int n;
int sum[N];
int dp(int i, int j){
if(i == j) return 0;//只有该一堆石子本身
int &v = f[i][j];
if(v != -1) return v;
v = 1e9;
for(int k = i; k < j; k++){
v = min(v, dp(i,k) + dp(k + 1,j) + sum[j] - sum[i - 1]);
}
return v;
}
int main(){
scanf("%d",&n);
for(int i = 1; i <= n; i++) scanf("%d",&sum[i]),sum[i] += sum[i - 1];
memset(f,-1,sizeof(f));
int v =0x3f3f3f3f;
v = min(v, dp(1,n));
printf("%d\n",v);
return 0;
}