线状DP(石子归并)

时间:2023-03-08 19:42:26

题意:有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 = ; i <= n; i++) cin>>a[i];
for(int i = ; i < n; i++){
sum[i][i] = a[i];
for(int j = i+; j <= n; j++){
sum[i][j] = sum[i][j-] + a[j];
//printf("%5d%5d%5d\n",i,j,sum[i][j]);
}
}
int j;
for(int len = ; len < n; len++){
for(int i = ; i < n-len+; 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+][j]+sum[i][j]);
// printf("%5d%5d%5d%5d\n",i,j,len,dp[i][j]);
}
}
}
cout << dp[][n]<<endl;
return ;
}