区间DP-石子合并(线性)

石子合并(一)

时间限制: 1000  ms  |  内存限制: 65535  KB
难度: 3
描述
    有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
输入
有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开
输出
输出总代价的最小值,占单独的一行
样例输入
3
1 2 3
7
13 7 8 16 21 4 18
样例输出
9
239
来源

 

题目在:

Here

 

这是一道经典的区间DP,做出来也花了不少时间,具体注释见代码。这里要注意的是sum数组是一个前缀和数组,需要注意的一点就是sum[i]=a[0]+a[1]+...+a[i];

sum[j]=a[0]+a[1]+a[2]+...+a[j],那么显然sum[i~j]=sum[j]-sum[i]+a[i],即sum[i~j]=sum[j]-sum[i-1].不然会减去a[i]。。

还有就是记忆化搜索这块儿,题目说最终合并为一堆,那么当本来只有一堆的时候合并代价是0,我写成了num[i]。注意这几点便可以把这道问题解决了。

 

/****************************************************
* author:crazy_石头
* Pro:石子合并问题
* algorithm:区间DP
* Time:420ms
* Judge Status:Accepted
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define rep(i,h,n) for(int i=(h);i<=(n);i++)
#define ms(a,b) memset((a),(b),sizeof(a))
#define eps 1e-6
#define INF 1<<29
#define LL __int64
const int maxn=200+5;
const int maxm=1000000+10;

int dp[maxn][maxn];
int sum[maxn],num[maxn];

inline int dfs(int i,int j)
{
    if(dp[i][j]!=INF)return dp[i][j];

    if(i==j)return dp[i][j]=0;//题目要合并为一堆,如果本身是一堆,那么不用合并,即代价为0;
    if(i+1==j)return dp[i][j]=num[i]+num[j];//两堆的话,合并代价等于这两堆的数量相加;
    if(i>j)return dp[i][j]=0;
    //其余情况,将大范围划小,则i~j间花费的费用等于i~k的代价加上k+1到j的代价并加上i~j间石子数目;
    for(int k=i;k>n)
    {
        int m;
        ms(sum,0);
        cin>>num[0];
        sum[0]=num[0];
        for(int i=1;i>num[i];
            sum[i]=sum[i-1]+num[i];
        }
        for(int i=0;i


 

你可能感兴趣的:(ACM_dp)