线状DP(石子归并)

Posted yoyo_sincerely

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线状DP(石子归并)相关的知识,希望对你有一定的参考价值。

题意:有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;
}

 

以上是关于线状DP(石子归并)的主要内容,如果未能解决你的问题,请参考以下文章

CSU 1592 石子归并(记忆化搜索 or 区间DP)

区间DP-----石子归并

51nod 1021 石子归并(dp)

石子归并

石子归并(区间DP)

台州 OJ 2793 石子归并 区间DP