CSU 1592 石子归并 相邻操作Dp问题

题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1592

题意:给定一堆石子,每次只能合并相邻两堆,每次的合并代价为两者石子数之和,求最后只剩下一堆时的最小合并代价。

刚开始,想到的是贪心,每次合并相邻和值最小的两堆就行了,这题和 POJ 3186  Treats for the Cows以及紫书上的“最优矩阵链乘”差不多,初看看似贪心,实则是Dp问题,但是都不会,呵呵。。。。只能看别人的代码,然后再写。。。

思路:用dp[i][j]表示合并区间[i,j]所需要的最小代价,那么,状态转移方程为:dp[i][j]=max(dp[i]k]+dp[k+1][j]+sum[i][j]),i<=k<=j。显然,对于我来讲,这个式子是不好直接实现递推的,但是发现这个递推式子和紫书上的最优矩阵链乘差不多,都表示:要求大区间的解,得先知道小区间的解,所以,可以把上述状态进行转换一下:用dp[i][j]表示,以i为起点,长度为j的解,则状态转移方程变为:dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k+1][j-k-1]+sum[i][i+j]);这样一来,就好实现递推方程了。


代码:

#include<iostream>
#include<cstdio>
#define maxn 110
#define INF 0x7fffffff

using namespace std;

int N,A[maxn],dp[maxn][maxn],sum[maxn];

int main(){
    //freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        cin>>N;
        for(int i=1;i<=N;i++)
            scanf("%d",A+i);
        sum[0]=0;
        for(int i=1;i<=N;i++)
            sum[i]=sum[i-1]+A[i];
        for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) dp[i][j]=INF;//初始化
        for(int i=1;i<=N;i++) dp[i][0]=0;//初始化
        for(int j=1;j<N;j++) for(int i=1;i+j<=N;i++)//先枚举长度j
            for(int k=0;k<j;k++)
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[i+k+1][j-k-1]+sum[i+j]-sum[i-1]);
        cout<<dp[1][N-1]<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值