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

来源:互联网 发布:淘宝诈骗卖家如何应对 编辑:程序博客网 时间:2024/05/22 15:04

石子合并(一)

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

 

题目在:

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 <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <queue>#include <vector>#include <algorithm>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 __int64const 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<j;k++)    dp[i][j]=min(dp[i][j],dfs(i,k)+dfs(k+1,j)+sum[j]-sum[i-1]);    return dp[i][j];}int main(){    int test,n;    while(cin>>n)    {        int m;        ms(sum,0);        cin>>num[0];        sum[0]=num[0];        for(int i=1;i<n;i++)        {            cin>>num[i];            sum[i]=sum[i-1]+num[i];        }        for(int i=0;i<n;i++)        {            for(int j=0;j<n;j++)            {                dp[i][j]=INF;            }        }        int res=dfs(0,n-1);        printf("%d\n",res);    }    return 0;}


 

原创粉丝点击