题意:有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。求将这N堆石子合并成一堆的总花费最小(或最大)。
dp[i][j]为从i到j的最小代价;sum为i到j的和;k用于分割dp[i][j];
动态转移方程为:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]);
#include <iostream> #include <algorithm> #include <stdlib.h> #include <time.h> #include <cmath> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <queue> #include <stack> #include <set> #define c_false ios_base::sync_with_stdio(false); cin.tie(0) #define INF 0x3f3f3f3f #define INFL 0x3f3f3f3f3f3f3f3f #define zero_(x,y) memset(x , y , sizeof(x)) #define zero(x) memset(x , 0 , sizeof(x)) #define MAX(x) memset(x , 0x3f ,sizeof(x)) using namespace std ; #define N 505 typedef long long LL ; int dp[N][N],sum[N][N],a[N]; int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int n; cin>>n; zero(sum); zero(dp); for(int i = 1; i <= n; i++) cin>>a[i]; for(int i = 1; i < n; i++){ sum[i][i] = a[i]; for(int j = i+1; j <= n; j++){ sum[i][j] = sum[i][j-1] + a[j]; //printf("%5d%5d%5d\n",i,j,sum[i][j]); } } int j; for(int len = 1; len < n; len++){ for(int i = 1; i < n-len+1; i++ ){ j = i+len; dp[i][j] = INF; for(int k = i; k < j; k++){ dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]+sum[i][j]); // printf("%5d%5d%5d%5d\n",i,j,len,dp[i][j]); } } } cout << dp[1][n]<<endl; return 0; }