线状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;
}
时间: 2024-12-23 05:00:14

线状DP(石子归并)的相关文章

石子归并(dp)

石子归并 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 89  Solved: 22 [Submit][Status][Web Board] Description 现在有n堆石子,第i堆有ai个石子.现在要把这些石子合并成一堆,每次只能合并相邻两个,每次合并的代价是两堆石子的总石子数.求合并所有石子的最小代价. Input 第一行包含一个整数T(T<=50),表示数据组数. 每组数据第一行包含一个整数n(2<=n<=100),表示石子的

51nod 1021 石子归并(dp)

51nod 1021 石子归并 题解:从i到j合并的最小值:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]); 最后dp[1][n]即为所求结果. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define CLR(a,b) memset((a),(b),sizeof((a))) 5 using name

石子归并-2:区间DP{环形}

题目描述 Description 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分. 输入描述 Input Description 数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数. 输出描述 Output Description 输出共2行,第1行为最小得分,第2行为最大得分. 样例输入

区间DP基础——石子归并

http://acm.nyist.net/JudgeOnline/problem.php?pid=737 石子归并:先枚举要合并的区间长,然后枚举相应的区间左端点,最后枚举区间中间的划分点,这样,就可以由小到大递推解决区间问题了. 转移方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]) 1 #include<iostream> 2 #include<cstdio> 3 #define INF

台州 OJ 2793 石子归并 区间DP

描述 有n堆石子排成一条直线,每堆石子有一定的重量.现在要合并这些石子成为一堆石子,但是每次只能合并相邻的两堆.每次合并需要消耗一定的体力,该体力为所合并的两堆石子的重量之和.问最少需要多少体力才能将n堆石子合并成一堆石子? 输入 输入只包含若干组数据.每组数据第一行包含一个正整数n(2<=n<=100),表示有n堆石子.接下来一行包含n个正整数a1,a2,a3,...,an(0<ai<=100,1<=i<=n). 输出 对应输入的数据,每行输出消耗的体力. dp[i]

【日常学习】【区间DP】codevs1048 石子归并题解

题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1].问安排怎样的合并顺序,能够使得总合并代价达到最小. 输入描述 Input Description 第一行一个整数n(n<=100) 第二行n个整数w1,w2...wn  (wi <= 100) 输出描述 Output Description 一个整数表示最小合并代价 样例输入 Sample Input 4 4 1 1 4 样

[51nod 1022] 石子归并v2 [dp+四边形不等式优化]

题面: 传送门 思路: 加强版的石子归并,现在朴素的区间dp无法解决问题了 首先我们破环成链,复制一条一样的链并粘贴到原来的链后面,变成一个2n长度的序列,在它上面dp,效率O(8n^3) 显然是过不了的,需要优化 注意:dp的转移如下:dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum(i,j)),其中sum(i,j)表示i到j的价值和,满足区间单调性 因此dp[i][j]也满足区间单调性,可以用四边形不等式优化 我们令s[i][j]等于让dp[i][j]取最小值的那个K

3002 石子归并 3

时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1].问安排怎样的合并顺序,能够使得总合并代价达到最小. 输入描述 Input Description 第一行一个整数n(n<=3000) 第二行n个整数w1,w2...wn  (wi <= 3000) 输出描述 Outpu

AC日记——石子归并 51nod 1021

石子归并 思路: 经典动态规划——归并类问题: 我们把状态划为n个,即1-n的n个长度为n个状态: 那么,每个长度为i的状态都可以由i-1个长度为i-1的状态推出: 所以,dp转移方程: dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algori